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 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s", 1709 bpp->bp_unchkpnm, p); 1710 1711 if (tm_tar_ops.tm_putdir != NULL) 1712 (void) (tm_tar_ops.tm_putdir)(fullpath, bpp->bp_tlmacl, 1713 bpp->bp_lcmd, bpp->bp_js); 1714 1715 apos = tlm_get_data_offset(bpp->bp_lcmd); 1716 bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed += 1717 apos - bpos; 1718 1719 return (0); 1720 } 1721 1722 1723 /* 1724 * backup_filev3 1725 * 1726 * Backup a file and update the bytes processed field of the 1727 * data server. 1728 * 1729 * Parameters: 1730 * bpp (input) - pointer to the backup parameters structure 1731 * pnp (input) - pointer to the path node 1732 * enp (input) - pointer to the entry node 1733 * 1734 * Returns: 1735 * 0: on success 1736 * != 0: otherwise 1737 */ 1738 static int 1739 backup_filev3(bk_param_v3_t *bpp, fst_node_t *pnp, 1740 fst_node_t *enp) 1741 { 1742 char *ent; 1743 longlong_t rv; 1744 longlong_t apos, bpos; 1745 acl_t *aclp = NULL; 1746 char *acltp; 1747 struct stat64 st; 1748 char fullpath[TLM_MAX_PATH_NAME]; 1749 char *p; 1750 1751 if (!bpp || !pnp || !enp) { 1752 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1753 return (-1); 1754 } 1755 1756 NDMP_LOG(LOG_DEBUG, "f(%s)", bpp->bp_tmp); 1757 1758 if (lstat64(bpp->bp_tmp, &st) != 0) 1759 return (0); 1760 1761 if (!S_ISLNK(bpp->bp_tlmacl->acl_attr.st_mode)) { 1762 if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) { 1763 NDMP_LOG(LOG_DEBUG, "acl_get error"); 1764 return (-1); 1765 } 1766 1767 if (aclp && 1768 (acltp = acl_totext(aclp, 1769 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) { 1770 (void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info, 1771 acltp, TLM_MAX_ACL_TXT); 1772 acl_free(aclp); 1773 free(acltp); 1774 } else { 1775 *bpp->bp_tlmacl->acl_info.attr_info = '\0'; 1776 } 1777 } 1778 1779 bpos = tlm_get_data_offset(bpp->bp_lcmd); 1780 ent = enp->tn_path ? enp->tn_path : ""; 1781 1782 p = pnp->tn_path + strlen(bpp->bp_chkpnm); 1783 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s", 1784 bpp->bp_unchkpnm, p); 1785 1786 if (tm_tar_ops.tm_putfile != NULL) 1787 rv = (tm_tar_ops.tm_putfile)(fullpath, ent, pnp->tn_path, 1788 bpp->bp_tlmacl, bpp->bp_cmds, bpp->bp_lcmd, bpp->bp_js, 1789 bpp->bp_session->hardlink_q); 1790 1791 apos = tlm_get_data_offset(bpp->bp_lcmd); 1792 bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed += 1793 apos - bpos; 1794 1795 return (rv < 0 ? rv : 0); 1796 } 1797 1798 1799 /* 1800 * check_bk_args 1801 * 1802 * Check the argument of the bpp. This is shared function between 1803 * timebk_v3 and lbrbk_v3 functions. The checks include: 1804 * - The bpp itself. 1805 * - If the session pointer of the bpp is valid. 1806 * - If the session connection to the DMA is closed. 1807 * - If the nlp pointer of the bpp is valid. 1808 * - If the backup is aborted. 1809 * 1810 * Parameters: 1811 * bpp (input) - pointer to the backup parameters structure 1812 * 1813 * Returns: 1814 * 0: if everything's OK 1815 * != 0: otherwise 1816 */ 1817 static int 1818 check_bk_args(bk_param_v3_t *bpp) 1819 { 1820 int rv; 1821 1822 if (!bpp) { 1823 rv = -1; 1824 NDMP_LOG(LOG_DEBUG, "Lost bpp"); 1825 } else if (!bpp->bp_session) { 1826 rv = -1; 1827 NDMP_LOG(LOG_DEBUG, "Session is NULL"); 1828 } else if (bpp->bp_session->ns_eof) { 1829 rv = -1; 1830 NDMP_LOG(LOG_INFO, 1831 "Connection client is closed for backup \"%s\"", 1832 bpp->bp_nlp->nlp_backup_path); 1833 } else if (!bpp->bp_nlp) { 1834 NDMP_LOG(LOG_DEBUG, "Lost nlp"); 1835 return (-1); 1836 } else if (bpp->bp_session->ns_data.dd_abort) { 1837 rv = -1; 1838 NDMP_LOG(LOG_INFO, "Backup aborted \"%s\"", 1839 bpp->bp_nlp->nlp_backup_path); 1840 } else 1841 rv = 0; 1842 1843 return (rv); 1844 } 1845 1846 1847 /* 1848 * shouldskip 1849 * 1850 * Determines if the current entry should be skipped or it 1851 * should be backed up. 1852 * 1853 * Parameters: 1854 * bpp (input) - pointer to the backup parameters structure 1855 * pnp (input) - pointer to the path node 1856 * enp (input) - pointer to the entry node 1857 * errp (output) - pointer to the error value that should be 1858 * returned by the caller 1859 * 1860 * Returns: 1861 * TRUE: if the entry should not be backed up 1862 * FALSE: otherwise 1863 */ 1864 static boolean_t 1865 shouldskip(bk_param_v3_t *bpp, fst_node_t *pnp, 1866 fst_node_t *enp, int *errp) 1867 { 1868 char *ent; 1869 boolean_t rv; 1870 struct stat64 *estp; 1871 1872 if (!bpp || !pnp || !enp || !errp) { 1873 NDMP_LOG(LOG_DEBUG, "Invalid argument"); 1874 return (TRUE); 1875 } 1876 1877 if (!enp->tn_path) { 1878 ent = ""; 1879 estp = pnp->tn_st; 1880 } else { 1881 ent = enp->tn_path; 1882 estp = enp->tn_st; 1883 } 1884 1885 /* 1886 * When excluding or skipping entries, FST_SKIP should be 1887 * returned, otherwise, 0 should be returned to 1888 * get other entries in the directory of this entry. 1889 */ 1890 if (!dbm_getone(bpp->bp_nlp->nlp_bkmap, (u_longlong_t)estp->st_ino)) { 1891 rv = TRUE; 1892 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0; 1893 NDMP_LOG(LOG_DEBUG, "Skipping %d %s/%s", 1894 *errp, pnp->tn_path, ent); 1895 } else if (tlm_is_excluded(pnp->tn_path, ent, bpp->bp_excls)) { 1896 rv = TRUE; 1897 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0; 1898 NDMP_LOG(LOG_DEBUG, "excl %d \"%s/%s\"", 1899 *errp, pnp->tn_path, ent); 1900 } else if (inexl(bpp->bp_nlp->nlp_exl, ent)) { 1901 rv = TRUE; 1902 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0; 1903 NDMP_LOG(LOG_DEBUG, "out %d \"%s/%s\"", 1904 *errp, pnp->tn_path, ent); 1905 } else if (!S_ISDIR(estp->st_mode) && 1906 !ininc(bpp->bp_nlp->nlp_inc, ent)) { 1907 rv = TRUE; 1908 *errp = 0; 1909 NDMP_LOG(LOG_DEBUG, "!in \"%s/%s\"", pnp->tn_path, ent); 1910 } else 1911 rv = FALSE; 1912 1913 return (rv); 1914 } 1915 1916 1917 /* 1918 * ischngd 1919 * 1920 * Check if the object specified should be backed up or not. 1921 * If stp belongs to a directory and if it is marked in the 1922 * bitmap vector, it shows that either the directory itself is 1923 * modified or there is something below it that will be backed 1924 * up. 1925 * 1926 * By setting ndmp_force_bk_dirs global variable to a non-zero 1927 * value, directories are backed up anyways. 1928 * 1929 * Backing up the directories unconditionally helps 1930 * restoring the metadata of directories as well, when one 1931 * of the objects below them are being restored. 1932 * 1933 * For non-directory objects, if the modification or change 1934 * time of the object is after the date specified by the 1935 * bk_selector_t, the the object must be backed up. 1936 */ 1937 static boolean_t 1938 ischngd(struct stat64 *stp, time_t t, ndmp_lbr_params_t *nlp) 1939 { 1940 boolean_t rv; 1941 1942 if (!stp) { 1943 rv = FALSE; 1944 NDMP_LOG(LOG_DEBUG, "stp is NULL"); 1945 } else if (!nlp) { 1946 rv = FALSE; 1947 NDMP_LOG(LOG_DEBUG, "nlp is NULL"); 1948 } else if (t == 0) { 1949 /* 1950 * if we are doing base backup then we do not need to 1951 * check the time, for we should backup everything. 1952 */ 1953 rv = TRUE; 1954 NDMP_LOG(LOG_DEBUG, "Base Backup"); 1955 } else if (S_ISDIR(stp->st_mode) && ndmp_force_bk_dirs) { 1956 rv = TRUE; 1957 NDMP_LOG(LOG_DEBUG, "d(%lu)", (uint_t)stp->st_ino); 1958 } else if (S_ISDIR(stp->st_mode) && 1959 dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino) && 1960 ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) || 1961 (NLP_ISTAR(nlp) && ndmp_tar_path_node))) { 1962 /* 1963 * If the object is a directory and it leads to a modified 1964 * object (that should be backed up) and for that type of 1965 * backup the path nodes should be backed up, then return 1966 * TRUE. 1967 * 1968 * This is required by some DMAs like Backup Express, which 1969 * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar) 1970 * for the intermediate directories of a modified object. 1971 * Other DMAs, like net_backup and net_worker, do not have such 1972 * requirement. This requirement makes sense for dump format 1973 * but for 'tar' format, it does not. In provision to the 1974 * NDMP-v4 spec, for 'tar' format the intermediate directories 1975 * need not to be reported. 1976 */ 1977 rv = TRUE; 1978 NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)stp->st_ino); 1979 } else if (stp->st_mtime > t) { 1980 rv = TRUE; 1981 NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu", 1982 (uint_t)stp->st_ino, (uint_t)stp->st_mtime, (uint_t)t); 1983 } else if (stp->st_ctime > t) { 1984 if (NLP_IGNCTIME(nlp)) { 1985 rv = FALSE; 1986 NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu", 1987 (uint_t)stp->st_ino, (uint_t)stp->st_ctime, 1988 (uint_t)t); 1989 } else { 1990 rv = TRUE; 1991 NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu", 1992 (uint_t)stp->st_ino, (uint_t)stp->st_ctime, 1993 (uint_t)t); 1994 } 1995 } else { 1996 rv = FALSE; 1997 NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu", 1998 (uint_t)stp->st_ino, (uint_t)stp->st_mtime, 1999 (uint_t)stp->st_ctime, (uint_t)t); 2000 } 2001 2002 return (rv); 2003 } 2004 2005 2006 /* 2007 * iscreated 2008 * 2009 * This function is used to check last mtime (currently inside the ACL 2010 * structure) instead of ctime for checking if the file is to be backed up 2011 * or not. See option "inc.lmtime" for more details 2012 */ 2013 /*ARGSUSED*/ 2014 int iscreated(ndmp_lbr_params_t *nlp, char *name, tlm_acls_t *tacl, 2015 time_t t) 2016 { 2017 int ret; 2018 acl_t *aclp = NULL; 2019 char *acltp; 2020 2021 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags); 2022 if (NLP_INCLMTIME(nlp) == FALSE) 2023 return (0); 2024 2025 ret = acl_get(name, ACL_NO_TRIVIAL, &aclp); 2026 if (ret != 0) { 2027 NDMP_LOG(LOG_DEBUG, 2028 "Error getting the acl information: err %d", ret); 2029 return (0); 2030 } 2031 if (aclp && (acltp = acl_totext(aclp, 2032 ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) { 2033 (void) strlcpy(tacl->acl_info.attr_info, acltp, 2034 TLM_MAX_ACL_TXT); 2035 acl_free(aclp); 2036 free(acltp); 2037 } 2038 2039 /* Need to add support for last mtime */ 2040 2041 return (0); 2042 } 2043 2044 /* 2045 * size_cb 2046 * 2047 * The callback function for calculating the size of 2048 * the backup path. This is used to get an estimate 2049 * of the progress of backup during NDMP backup 2050 */ 2051 static int 2052 size_cb(void *arg, fst_node_t *pnp, fst_node_t *enp) 2053 { 2054 struct stat64 *stp; 2055 2056 stp = enp->tn_path ? enp->tn_st : pnp->tn_st; 2057 *((u_longlong_t *)arg) += stp->st_size; 2058 2059 return (0); 2060 } 2061 2062 /* 2063 * timebk_v3 2064 * 2065 * The callback function for backing up objects based on 2066 * their time stamp. This is shared between token-based 2067 * and level-based backup, which look at the time stamps 2068 * of the objects to determine if they should be backed 2069 * up. 2070 * 2071 * Parameters: 2072 * arg (input) - pointer to the backup parameters structure 2073 * pnp (input) - pointer to the path node 2074 * enp (input) - pointer to the entry node 2075 * 2076 * Returns: 2077 * 0: if backup should continue 2078 * -1: if the backup should be stopped 2079 * FST_SKIP: if backing up the current directory is enough 2080 */ 2081 static int 2082 timebk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp) 2083 { 2084 char *ent; 2085 int rv; 2086 time_t t; 2087 bk_param_v3_t *bpp; 2088 struct stat64 *stp; 2089 fs_fhandle_t *fhp; 2090 2091 bpp = (bk_param_v3_t *)arg; 2092 2093 rv = check_bk_args(bpp); 2094 if (rv != 0) 2095 return (rv); 2096 2097 stp = enp->tn_path ? enp->tn_st : pnp->tn_st; 2098 if (shouldskip(bpp, pnp, enp, &rv)) 2099 return (rv); 2100 2101 if (enp->tn_path) { 2102 ent = enp->tn_path; 2103 stp = enp->tn_st; 2104 fhp = enp->tn_fh; 2105 } else { 2106 ent = ""; 2107 stp = pnp->tn_st; 2108 fhp = pnp->tn_fh; 2109 } 2110 2111 2112 if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) { 2113 NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent); 2114 return (FST_SKIP); 2115 } 2116 if (NLP_ISSET(bpp->bp_nlp, NLPF_TOKENBK)) 2117 t = bpp->bp_nlp->nlp_tokdate; 2118 else if (NLP_ISSET(bpp->bp_nlp, NLPF_LEVELBK)) { 2119 t = bpp->bp_nlp->nlp_ldate; 2120 } else { 2121 NDMP_LOG(LOG_DEBUG, "Unknown backup type on \"%s/%s\"", 2122 pnp->tn_path, ent); 2123 return (-1); 2124 } 2125 2126 if (S_ISDIR(stp->st_mode)) { 2127 bpp->bp_tlmacl->acl_dir_fh = *fhp; 2128 (void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks, 2129 bpp->bp_tmp, stp); 2130 2131 if (ischngd(stp, t, bpp->bp_nlp)) { 2132 (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp, 2133 sizeof (struct stat64)); 2134 rv = backup_dirv3(bpp, pnp, enp); 2135 } 2136 } else { 2137 if (ischngd(stp, t, bpp->bp_nlp) || 2138 iscreated(bpp->bp_nlp, bpp->bp_tmp, bpp->bp_tlmacl, t)) { 2139 rv = 0; 2140 (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp, 2141 sizeof (struct stat64)); 2142 bpp->bp_tlmacl->acl_fil_fh = *fhp; 2143 (void) backup_filev3(bpp, pnp, enp); 2144 } 2145 } 2146 2147 return (rv); 2148 } 2149 2150 2151 /* 2152 * lbrbk_v3 2153 * 2154 * The callback function for backing up objects based on 2155 * their archive directory bit. This is used in LBR-type 2156 * backup. In which the objects are backed up if their 2157 * archive bit is set. 2158 * 2159 * Parameters: 2160 * arg (input) - pointer to the backup parameters structure 2161 * pnp (input) - pointer to the path node 2162 * enp (input) - pointer to the entry node 2163 * 2164 * Returns: 2165 * 0: if backup should continue 2166 * -1: if the backup should be stopped 2167 * FST_SKIP: if backing up the current directory is enough 2168 */ 2169 static int 2170 lbrbk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp) 2171 { 2172 char *ent; 2173 int rv; 2174 bk_param_v3_t *bpp; 2175 struct stat64 *stp; 2176 fs_fhandle_t *fhp; 2177 2178 bpp = (bk_param_v3_t *)arg; 2179 rv = check_bk_args(bpp); 2180 if (rv != 0) 2181 return (rv); 2182 2183 stp = enp->tn_path ? enp->tn_st : pnp->tn_st; 2184 if (shouldskip(bpp, pnp, enp, &rv)) 2185 return (rv); 2186 2187 if (enp->tn_path) { 2188 ent = enp->tn_path; 2189 stp = enp->tn_st; 2190 fhp = enp->tn_fh; 2191 } else { 2192 ent = ""; 2193 stp = pnp->tn_st; 2194 fhp = pnp->tn_fh; 2195 } 2196 2197 if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) { 2198 NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent); 2199 return (FST_SKIP); 2200 } 2201 if (!NLP_ISSET(bpp->bp_nlp, NLPF_LBRBK)) { 2202 NDMP_LOG(LOG_DEBUG, "!NLPF_LBRBK"); 2203 return (-1); 2204 } 2205 2206 if (S_ISDIR(stp->st_mode)) { 2207 bpp->bp_tlmacl->acl_dir_fh = *fhp; 2208 (void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks, 2209 bpp->bp_tmp, stp); 2210 2211 if (SHOULD_LBRBK(bpp)) { 2212 bpp->bp_tlmacl->acl_attr = *stp; 2213 rv = backup_dirv3(bpp, pnp, enp); 2214 } 2215 } else if (SHOULD_LBRBK(bpp)) { 2216 rv = 0; 2217 bpp->bp_tlmacl->acl_attr = *stp; 2218 bpp->bp_tlmacl->acl_fil_fh = *fhp; 2219 (void) backup_filev3(bpp, pnp, enp); 2220 } 2221 2222 return (rv); 2223 } 2224 2225 2226 /* 2227 * backup_reader_v3 2228 * 2229 * The reader thread for the backup. It sets up the callback 2230 * parameters and traverses the backup hierarchy in level-order 2231 * way. 2232 * 2233 * Parameters: 2234 * jname (input) - name assigned to the current backup for 2235 * job stats strucure 2236 * nlp (input) - pointer to the nlp structure 2237 * cmds (input) - pointer to the tlm_commands_t structure 2238 * 2239 * Returns: 2240 * 0: on success 2241 * != 0: otherwise 2242 */ 2243 static int 2244 backup_reader_v3(backup_reader_arg_t *argp) 2245 { 2246 int rv; 2247 tlm_cmd_t *lcmd; 2248 tlm_acls_t tlm_acls; 2249 longlong_t bpos, n; 2250 bk_param_v3_t bp; 2251 fs_traverse_t ft; 2252 char *jname; 2253 ndmp_lbr_params_t *nlp; 2254 tlm_commands_t *cmds; 2255 2256 if (!argp) 2257 return (-1); 2258 2259 jname = argp->br_jname; 2260 nlp = argp->br_nlp; 2261 cmds = argp->br_cmds; 2262 2263 rv = 0; 2264 lcmd = cmds->tcs_command; 2265 lcmd->tc_ref++; 2266 cmds->tcs_reader_count++; 2267 2268 (void) memset(&tlm_acls, 0, sizeof (tlm_acls)); 2269 2270 /* NDMP parameters */ 2271 bp.bp_session = nlp->nlp_session; 2272 bp.bp_nlp = nlp; 2273 2274 /* LBR-related parameters */ 2275 bp.bp_js = tlm_ref_job_stats(jname); 2276 bp.bp_cmds = cmds; 2277 bp.bp_lcmd = lcmd; 2278 bp.bp_tlmacl = &tlm_acls; 2279 bp.bp_opr = 0; 2280 2281 /* release the parent thread, after referencing the job stats */ 2282 (void) pthread_barrier_wait(&argp->br_barrier); 2283 2284 bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME); 2285 if (!bp.bp_tmp) 2286 return (-1); 2287 2288 /* 2289 * Make the checkpointed paths for traversing the 2290 * backup hierarchy, if we make the checkpoint. 2291 */ 2292 bp.bp_unchkpnm = nlp->nlp_backup_path; 2293 if (!NLP_ISCHKPNTED(nlp)) { 2294 tlm_acls.acl_checkpointed = TRUE; 2295 bp.bp_chkpnm = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME); 2296 if (!bp.bp_chkpnm) { 2297 NDMP_FREE(bp.bp_tmp); 2298 return (-1); 2299 } 2300 (void) tlm_build_snapshot_name(nlp->nlp_backup_path, 2301 bp.bp_chkpnm, nlp->nlp_jstat->js_job_name); 2302 } else { 2303 tlm_acls.acl_checkpointed = FALSE; 2304 bp.bp_chkpnm = nlp->nlp_backup_path; 2305 } 2306 bp.bp_excls = ndmpd_make_exc_list(); 2307 2308 /* set traversing arguments */ 2309 ft.ft_path = nlp->nlp_backup_path; 2310 ft.ft_lpath = bp.bp_chkpnm; 2311 2312 NDMP_LOG(LOG_DEBUG, "path %s lpath %s", ft.ft_path, ft.ft_lpath); 2313 if (NLP_ISSET(nlp, NLPF_TOKENBK) || NLP_ISSET(nlp, NLPF_LEVELBK)) { 2314 ft.ft_callbk = timebk_v3; 2315 tlm_acls.acl_clear_archive = FALSE; 2316 } else if (NLP_ISSET(nlp, NLPF_LBRBK)) { 2317 ft.ft_callbk = lbrbk_v3; 2318 tlm_acls.acl_clear_archive = FALSE; 2319 2320 NDMP_LOG(LOG_DEBUG, "bp_opr %x clr_arc %c", 2321 bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive)); 2322 } else { 2323 rv = -1; 2324 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR, 2325 "Unknow backup type.\n"); 2326 } 2327 ft.ft_arg = &bp; 2328 ft.ft_logfp = (ft_log_t)ndmp_log; 2329 ft.ft_flags = FST_VERBOSE; /* Solaris */ 2330 2331 /* take into account the header written to the stream so far */ 2332 n = tlm_get_data_offset(lcmd); 2333 nlp->nlp_session->ns_data.dd_module.dm_stats.ms_bytes_processed = n; 2334 2335 if (rv == 0) { 2336 /* start traversing the hierarchy and actual backup */ 2337 rv = traverse_level(&ft); 2338 if (rv == 0) { 2339 /* write the trailer and update the bytes processed */ 2340 bpos = tlm_get_data_offset(lcmd); 2341 (void) write_tar_eof(lcmd); 2342 n = tlm_get_data_offset(lcmd) - bpos; 2343 nlp->nlp_session-> 2344 ns_data.dd_module.dm_stats.ms_bytes_processed += n; 2345 } 2346 } 2347 2348 if (!NLP_ISCHKPNTED(nlp)) 2349 NDMP_FREE(bp.bp_chkpnm); 2350 NDMP_FREE(bp.bp_tmp); 2351 NDMP_FREE(bp.bp_excls); 2352 2353 cmds->tcs_reader_count--; 2354 lcmd->tc_writer = TLM_STOP; 2355 tlm_release_reader_writer_ipc(lcmd); 2356 tlm_un_ref_job_stats(jname); 2357 return (rv); 2358 2359 } 2360 2361 2362 /* 2363 * tar_backup_v3 2364 * 2365 * Traverse the backup hierarchy if needed and make the bitmap. 2366 * Then launch reader and writer threads to do the actual backup. 2367 * 2368 * Parameters: 2369 * session (input) - pointer to the session 2370 * params (input) - pointer to the parameters structure 2371 * nlp (input) - pointer to the nlp structure 2372 * jname (input) - job name 2373 * 2374 * Returns: 2375 * 0: on success 2376 * != 0: otherwise 2377 */ 2378 static int 2379 tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 2380 ndmp_lbr_params_t *nlp, char *jname) 2381 { 2382 tlm_commands_t *cmds; 2383 backup_reader_arg_t arg; 2384 pthread_t rdtp; 2385 char info[256]; 2386 int result; 2387 ndmp_context_t nctx; 2388 int err; 2389 2390 if (ndmp_get_bk_dir_ino(nlp)) 2391 return (-1); 2392 2393 result = err = 0; 2394 2395 /* exit as if there was an internal error */ 2396 if (session->ns_eof) 2397 return (-1); 2398 2399 if (!session->ns_data.dd_abort) { 2400 if (backup_alloc_structs_v3(session, jname) < 0) { 2401 nlp->nlp_bkmap = -1; 2402 return (-1); 2403 } 2404 2405 if (ndmpd_mark_inodes_v3(session, nlp) != 0) { 2406 if (nlp->nlp_bkmap != -1) { 2407 (void) dbm_free(nlp->nlp_bkmap); 2408 nlp->nlp_bkmap = -1; 2409 } 2410 free_structs_v3(session, jname); 2411 return (-1); 2412 } 2413 2414 nlp->nlp_jstat->js_start_ltime = time(NULL); 2415 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime; 2416 nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate; 2417 2418 cmds = &nlp->nlp_cmds; 2419 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN; 2420 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN; 2421 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN; 2422 2423 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) { 2424 free_structs_v3(session, jname); 2425 return (-1); 2426 } 2427 2428 NDMP_LOG(LOG_DEBUG, 2429 "Backing up \"%s\" started.", nlp->nlp_backup_path); 2430 2431 /* Plug-in module */ 2432 if (ndmp_pl != NULL && 2433 ndmp_pl->np_pre_backup != NULL) { 2434 (void) memset(&nctx, 0, sizeof (ndmp_context_t)); 2435 nctx.nc_plversion = ndmp_pl->np_plversion; 2436 nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH); 2437 nctx.nc_cmds = cmds; 2438 if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx, 2439 nlp->nlp_backup_path)) != 0) { 2440 NDMP_LOG(LOG_DEBUG, "Pre-backup plug-in: %m"); 2441 goto backup_out; 2442 } 2443 } 2444 2445 (void) memset(&arg, 0, sizeof (backup_reader_arg_t)); 2446 arg.br_jname = jname; 2447 arg.br_nlp = nlp; 2448 arg.br_cmds = cmds; 2449 2450 (void) pthread_barrier_init(&arg.br_barrier, 0, 2); 2451 2452 err = pthread_create(&rdtp, NULL, (funct_t)backup_reader_v3, 2453 (void *)&arg); 2454 if (err == 0) { 2455 (void) pthread_barrier_wait(&arg.br_barrier); 2456 (void) pthread_barrier_destroy(&arg.br_barrier); 2457 } else { 2458 (void) pthread_barrier_destroy(&arg.br_barrier); 2459 free_structs_v3(session, jname); 2460 NDMP_LOG(LOG_DEBUG, "Launch backup_reader_v3: %m"); 2461 return (-1); 2462 } 2463 2464 if ((err = ndmp_tar_writer(session, params, cmds)) != 0) 2465 result = EIO; 2466 2467 nlp->nlp_jstat->js_stop_time = time(NULL); 2468 2469 (void) snprintf(info, sizeof (info), 2470 "Runtime [%s] %llu bytes (%llu): %d seconds\n", 2471 nlp->nlp_backup_path, 2472 session->ns_data.dd_module.dm_stats.ms_bytes_processed, 2473 session->ns_data.dd_module.dm_stats.ms_bytes_processed, 2474 nlp->nlp_jstat->js_stop_time - 2475 nlp->nlp_jstat->js_start_ltime); 2476 MOD_LOGV3(params, NDMP_LOG_NORMAL, info); 2477 2478 ndmp_wait_for_reader(cmds); 2479 (void) pthread_join(rdtp, NULL); 2480 2481 /* exit as if there was an internal error */ 2482 if (session->ns_eof) { 2483 result = EPIPE; 2484 err = -1; 2485 } 2486 if (!session->ns_data.dd_abort) { 2487 ndmpd_audit_backup(session->ns_connection, 2488 nlp->nlp_backup_path, 2489 session->ns_data.dd_data_addr.addr_type, 2490 session->ns_tape.td_adapter_name, result); 2491 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" Finished.", 2492 nlp->nlp_backup_path); 2493 } 2494 } 2495 2496 if (session->ns_data.dd_abort) { 2497 ndmpd_audit_backup(session->ns_connection, 2498 nlp->nlp_backup_path, 2499 session->ns_data.dd_data_addr.addr_type, 2500 session->ns_tape.td_adapter_name, EINTR); 2501 NDMP_LOG(LOG_DEBUG, 2502 "Backing up \"%s\" aborted.", nlp->nlp_backup_path); 2503 err = -1; 2504 } else { 2505 2506 backup_out: 2507 /* Plug-in module */ 2508 if (ndmp_pl != NULL && 2509 ndmp_pl->np_post_backup != NULL && 2510 ndmp_pl->np_post_backup(ndmp_pl, &nctx, err) == -1) { 2511 NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m"); 2512 return (-1); 2513 } 2514 } 2515 2516 free_structs_v3(session, jname); 2517 return (err); 2518 } 2519 2520 /* 2521 * get_backup_size 2522 * 2523 * Find the estimate of backup size. This is used to get an estimate 2524 * of the progress of backup during NDMP backup. 2525 */ 2526 void 2527 get_backup_size(ndmpd_session_t *session, char *path) 2528 { 2529 fs_traverse_t ft; 2530 u_longlong_t bk_size; 2531 int rv; 2532 2533 if (path == NULL) 2534 return; 2535 2536 bk_size = 0; 2537 2538 /* set traversing arguments */ 2539 ft.ft_path = path; 2540 ft.ft_lpath = path; 2541 2542 ft.ft_callbk = size_cb; 2543 ft.ft_arg = &bk_size; 2544 ft.ft_logfp = (ft_log_t)ndmp_log; 2545 ft.ft_flags = FST_VERBOSE; /* Solaris */ 2546 2547 if ((rv = traverse_level(&ft)) != 0) { 2548 NDMP_LOG(LOG_DEBUG, "bksize err=%d", rv); 2549 bk_size = 0; 2550 } else { 2551 NDMP_LOG(LOG_DEBUG, "bksize %lld, %lldKB, %lldMB\n", 2552 bk_size, bk_size / 1024, bk_size /(1024 * 1024)); 2553 } 2554 session->ns_data.dd_data_size = bk_size; 2555 } 2556 2557 /* 2558 * get_rs_path_v3 2559 * 2560 * Find the restore path 2561 */ 2562 ndmp_error 2563 get_rs_path_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 2564 { 2565 char *dp; 2566 ndmp_error rv; 2567 mem_ndmp_name_v3_t *ep; 2568 int i, nm_cnt; 2569 char *nm_dpath_list[MULTIPLE_DEST_DIRS]; 2570 static char mdest_buf[256]; 2571 2572 *mdest_buf = 0; 2573 *nm_dpath_list = ""; 2574 for (i = 0, nm_cnt = 0; i < (int)nlp->nlp_nfiles; i++) { 2575 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i); 2576 if (!ep) { 2577 NDMP_LOG(LOG_DEBUG, "Can't get Nlist[%d]", i); 2578 return (NDMP_ILLEGAL_ARGS_ERR); 2579 } 2580 if (strcmp(nm_dpath_list[nm_cnt], ep->nm3_dpath) != 0 && 2581 nm_cnt < MULTIPLE_DEST_DIRS - 1) 2582 nm_dpath_list[++nm_cnt] = ep->nm3_dpath; 2583 } 2584 2585 multiple_dest_restore = (nm_cnt > 1); 2586 nlp->nlp_restore_path = mdest_buf; 2587 2588 for (i = 1; i < nm_cnt + 1; i++) { 2589 if (ISDEFINED(nm_dpath_list[i])) 2590 dp = nm_dpath_list[i]; 2591 else 2592 /* the default destination path is backup directory */ 2593 dp = nlp->nlp_backup_path; 2594 2595 /* check the destination directory exists and is writable */ 2596 if (!fs_volexist(dp)) { 2597 rv = NDMP_ILLEGAL_ARGS_ERR; 2598 MOD_LOGV3(params, NDMP_LOG_ERROR, 2599 "Invalid destination path volume \"%s\".\n", dp); 2600 } else if (!voliswr(dp)) { 2601 rv = NDMP_ILLEGAL_ARGS_ERR; 2602 MOD_LOGV3(params, NDMP_LOG_ERROR, 2603 "The destination path volume" 2604 " is not writable \"%s\".\n", dp); 2605 } else { 2606 rv = NDMP_NO_ERR; 2607 (void) strlcat(nlp->nlp_restore_path, dp, 2608 sizeof (mdest_buf)); 2609 NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", dp); 2610 } 2611 2612 /* 2613 * Exit if there is an error or it is not a multiple 2614 * destination restore mode 2615 */ 2616 if (rv != NDMP_NO_ERR || !multiple_dest_restore) 2617 break; 2618 2619 if (i < nm_cnt) 2620 (void) strlcat(nlp->nlp_restore_path, ", ", 2621 sizeof (mdest_buf)); 2622 } 2623 2624 return (rv); 2625 } 2626 2627 2628 /* 2629 * fix_nlist_v3 2630 * 2631 * Check if the recovery list is valid and fix it if there are some 2632 * unspecified entries in it. It checks for original, destination 2633 * and new path for all NDMP names provided inside the list. 2634 * 2635 * V3: dpath is the destination directory. If newnm is not NULL, the 2636 * destination path is dpath/newnm. Otherwise the destination path is 2637 * dpath/opath_last_node, where opath_last_node is the last node in opath. 2638 * 2639 * V4: If newnm is not NULL, dpath is the destination directory, and 2640 * dpath/newnm is the destination path. If newnm is NULL, dpath is 2641 * the destination path (opath is not involved in forming destination path). 2642 */ 2643 ndmp_error 2644 fix_nlist_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 2645 ndmp_lbr_params_t *nlp) 2646 { 2647 char *cp, *buf, *bp; 2648 int i, n; 2649 int iswrbk; 2650 int bvexists; 2651 ndmp_error rv; 2652 mem_ndmp_name_v3_t *ep; 2653 char *dp; 2654 char *nm; 2655 int existsvol; 2656 int isrwdst; 2657 2658 buf = ndmp_malloc(TLM_MAX_PATH_NAME); 2659 if (!buf) { 2660 MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n"); 2661 return (NDMP_NO_MEM_ERR); 2662 } 2663 2664 bvexists = fs_volexist(nlp->nlp_backup_path); 2665 iswrbk = voliswr(nlp->nlp_backup_path); 2666 2667 rv = NDMP_NO_ERR; 2668 n = session->ns_data.dd_nlist_len; 2669 for (i = 0; i < n; i++) { 2670 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i); 2671 if (!ep) 2672 continue; 2673 2674 /* chop off the trailing slashes */ 2675 chopslash(ep->nm3_opath); 2676 2677 chopslash(ep->nm3_dpath); 2678 chopslash(ep->nm3_newnm); 2679 2680 /* existing and non-empty destination path */ 2681 if (ISDEFINED(ep->nm3_dpath)) { 2682 dp = ep->nm3_dpath; 2683 existsvol = fs_volexist(dp); 2684 isrwdst = voliswr(dp); 2685 } else { 2686 /* the default destination path is backup directory */ 2687 dp = nlp->nlp_backup_path; 2688 existsvol = bvexists; 2689 isrwdst = iswrbk; 2690 } 2691 2692 /* check the destination directory exists and is writable */ 2693 if (!existsvol) { 2694 rv = NDMP_ILLEGAL_ARGS_ERR; 2695 MOD_LOGV3(params, NDMP_LOG_ERROR, 2696 "Invalid destination path volume " 2697 "\"%s\".\n", dp); 2698 break; 2699 } 2700 if (!isrwdst) { 2701 rv = NDMP_ILLEGAL_ARGS_ERR; 2702 MOD_LOGV3(params, NDMP_LOG_ERROR, 2703 "The destination path volume is not " 2704 "writable \"%s\".\n", dp); 2705 break; 2706 } 2707 2708 /* 2709 * If new name is not specified, the default new name is 2710 * the last component of the original path, if any 2711 * (except in V4). 2712 */ 2713 if (session->ns_protocol_version == NDMPV4) { 2714 nm = ep->nm3_newnm; 2715 } else { 2716 if (ISDEFINED(ep->nm3_newnm)) { 2717 nm = ep->nm3_newnm; 2718 } else { 2719 /* 2720 * Find the last component of nm3_opath. 2721 * nm3_opath has no trailing '/'. 2722 */ 2723 char *p = strrchr(ep->nm3_opath, '/'); 2724 nm = p? p : ep->nm3_opath; 2725 } 2726 } 2727 2728 bp = joinpath(buf, dp, nm); 2729 if (!bp) { 2730 /* 2731 * Note: What should be done with this entry? 2732 * We leave it untouched for now, hence no path in 2733 * the backup image matches with this entry and will 2734 * be reported as not found. 2735 */ 2736 MOD_LOGV3(params, NDMP_LOG_ERROR, 2737 "Destination path too long(%s/%s)", dp, nm); 2738 continue; 2739 } 2740 cp = strdup(bp); 2741 if (!cp) { 2742 MOD_LOGV3(params, NDMP_LOG_ERROR, 2743 "Insufficient memory.\n"); 2744 rv = NDMP_NO_MEM_ERR; 2745 break; 2746 } 2747 free(ep->nm3_dpath); 2748 ep->nm3_dpath = cp; 2749 NDMP_FREE(ep->nm3_newnm); 2750 2751 bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath); 2752 if (!bp) { 2753 /* 2754 * Note: The same problem of above with long path. 2755 */ 2756 MOD_LOGV3(params, NDMP_LOG_ERROR, 2757 "Path too long(%s/%s)", 2758 nlp->nlp_backup_path, ep->nm3_opath); 2759 continue; 2760 } 2761 cp = strdup(bp); 2762 if (!cp) { 2763 MOD_LOGV3(params, NDMP_LOG_ERROR, 2764 "Insufficient memory.\n"); 2765 rv = NDMP_NO_MEM_ERR; 2766 break; 2767 } 2768 NDMP_FREE(ep->nm3_opath); 2769 ep->nm3_opath = cp; 2770 2771 NDMP_LOG(LOG_DEBUG, "orig[%d]: \"%s\"", i, ep->nm3_opath); 2772 if (ep->nm3_dpath) { 2773 NDMP_LOG(LOG_DEBUG, 2774 "dest[%d]: \"%s\"", i, ep->nm3_dpath); 2775 } else { 2776 NDMP_LOG(LOG_DEBUG, "dest[%d]: \"%s\"", i, "NULL"); 2777 } 2778 } 2779 2780 free(buf); 2781 2782 return (rv); 2783 } 2784 2785 2786 /* 2787 * allvalidfh 2788 * 2789 * Run a sanity check on the file history info. The file history 2790 * info is the offset of the record starting the entry on the tape 2791 * and is used in DAR (direct access restore mode). 2792 */ 2793 static boolean_t 2794 allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params) 2795 { 2796 int i, n; 2797 boolean_t rv; 2798 mem_ndmp_name_v3_t *ep; 2799 2800 rv = TRUE; 2801 n = session->ns_data.dd_nlist_len; 2802 for (i = 0; i < n; i++) { 2803 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i); 2804 if (!ep) 2805 continue; 2806 /* 2807 * The fh_info's sent from the client are multiples 2808 * of RECORDSIZE which is 512 bytes. 2809 * 2810 * All our fh_info's are at the RECORDSIZE boundary. If there 2811 * is any fh_info that is less than RECORDSIZE (this covers 0 2812 * and -1 values too), then the result is that DAR cannot be 2813 * done. 2814 */ 2815 if (ep->nm3_fh_info < RECORDSIZE || 2816 ep->nm3_fh_info % RECORDSIZE != 0) { 2817 rv = FALSE; 2818 break; 2819 } 2820 } 2821 2822 return (rv); 2823 } 2824 2825 2826 /* 2827 * log_rs_params_v3 2828 * 2829 * Log a copy of all values of the restore parameters 2830 */ 2831 void 2832 log_rs_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 2833 ndmp_lbr_params_t *nlp) 2834 { 2835 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Restoring to \"%s\".\n", 2836 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL"); 2837 2838 if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) { 2839 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Tape server: local.\n"); 2840 MOD_LOGV3(params, NDMP_LOG_NORMAL, 2841 "Tape record size: %d.\n", 2842 session->ns_mover.md_record_size); 2843 } else if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP) 2844 MOD_LOGV3(params, NDMP_LOG_NORMAL, 2845 "Tape server: remote at %s:%d.\n", 2846 inet_ntoa(IN_ADDR(session->ns_data.dd_data_addr.tcp_ip_v3)), 2847 session->ns_data.dd_data_addr.tcp_port_v3); 2848 else 2849 MOD_LOGV3(params, NDMP_LOG_ERROR, 2850 "Unknown tape server address type.\n"); 2851 2852 if (NLP_ISSET(nlp, NLPF_DIRECT)) 2853 MOD_LOGV3(params, NDMP_LOG_NORMAL, 2854 "Direct Access Restore.\n"); 2855 } 2856 2857 2858 /* 2859 * send_unrecovered_list_v3 2860 * 2861 * Create the list of files that were in restore list but 2862 * not recovered due to some errors. 2863 */ 2864 int 2865 send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp) 2866 { 2867 int i, rv; 2868 int err; 2869 2870 if (!params) { 2871 NDMP_LOG(LOG_DEBUG, "params == NULL"); 2872 return (-1); 2873 } 2874 if (!nlp) { 2875 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 2876 return (-1); 2877 } 2878 2879 if (nlp->nlp_lastidx != -1) { 2880 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)nlp->nlp_lastidx)) 2881 err = ENOENT; 2882 else 2883 err = 0; 2884 (void) ndmp_send_recovery_stat_v3(params, nlp, 2885 nlp->nlp_lastidx, err); 2886 nlp->nlp_lastidx = -1; 2887 } 2888 2889 rv = 0; 2890 for (i = 0; i < (int)nlp->nlp_nfiles; i++) { 2891 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)i)) { 2892 rv = ndmp_send_recovery_stat_v3(params, nlp, i, ENOENT); 2893 if (rv < 0) 2894 break; 2895 } 2896 } 2897 2898 return (rv); 2899 } 2900 2901 2902 2903 /* 2904 * restore_dar_alloc_structs_v3 2905 * 2906 * Allocates the necessary structures for running DAR restore. 2907 * It just creates the reader writer IPC. 2908 * This function is called for each entry in the restore entry list. 2909 * 2910 * Parameters: 2911 * session (input) - pointer to the session 2912 * jname (input) - Job name 2913 * 2914 * Returns: 2915 * 0: on success 2916 * -1: on error 2917 */ 2918 int 2919 restore_dar_alloc_structs_v3(ndmpd_session_t *session, char *jname) 2920 { 2921 long xfer_size; 2922 ndmp_lbr_params_t *nlp; 2923 tlm_commands_t *cmds; 2924 2925 nlp = ndmp_get_nlp(session); 2926 if (!nlp) { 2927 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 2928 return (-1); 2929 } 2930 2931 cmds = &nlp->nlp_cmds; 2932 (void) memset(cmds, 0, sizeof (*cmds)); 2933 2934 xfer_size = ndmp_buffer_get_size(session); 2935 cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size); 2936 if (!cmds->tcs_command) { 2937 tlm_un_ref_job_stats(jname); 2938 return (-1); 2939 } 2940 2941 return (0); 2942 } 2943 2944 2945 /* 2946 * free_dar_structs_v3 2947 * 2948 * To free the structures were created by restore_dar_alloc_structs_v3. 2949 * This funnction is called for each entry in restore entry list. 2950 * 2951 * Parameters: 2952 * session (input) - pointer to the session 2953 * jname (input) - job name 2954 * 2955 * Returns: 2956 * NONE 2957 */ 2958 /*ARGSUSED*/ 2959 static void 2960 free_dar_structs_v3(ndmpd_session_t *session, char *jname) 2961 { 2962 ndmp_lbr_params_t *nlp; 2963 tlm_commands_t *cmds; 2964 2965 nlp = ndmp_get_nlp(session); 2966 if (!nlp) { 2967 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 2968 return; 2969 } 2970 cmds = &nlp->nlp_cmds; 2971 if (!cmds) { 2972 NDMP_LOG(LOG_DEBUG, "cmds == NULL"); 2973 return; 2974 } 2975 2976 if (cmds->tcs_command) { 2977 if (cmds->tcs_command->tc_buffers != NULL) 2978 tlm_release_reader_writer_ipc(cmds->tcs_command); 2979 else 2980 NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL"); 2981 cmds->tcs_command = NULL; 2982 } else 2983 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL"); 2984 } 2985 2986 2987 /* 2988 * ndmp_dar_tar_init_v3 2989 * 2990 * Constructor for the DAR restore. Creates job name, allocates structures 2991 * needed for keeping the statistics, and reports the start of restore action. 2992 * It is called once for each DAR restore request. 2993 * 2994 * Parameters: 2995 * session (input) - pointer to the session 2996 * nlp (input) - pointer to the nlp structure 2997 * 2998 * Returns: 2999 * char pointer: on success 3000 * NULL: on error 3001 */ 3002 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session, 3003 ndmp_lbr_params_t *nlp) 3004 { 3005 char *jname; 3006 3007 jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME); 3008 3009 if (!jname) 3010 return (NULL); 3011 3012 (void) ndmp_new_job_name(jname); 3013 3014 if (!nlp) { 3015 free(jname); 3016 NDMP_LOG(LOG_DEBUG, "nlp == NULL"); 3017 return (NULL); 3018 } 3019 3020 nlp->nlp_jstat = tlm_new_job_stats(jname); 3021 if (!nlp->nlp_jstat) { 3022 free(jname); 3023 NDMP_LOG(LOG_DEBUG, "Creating job stats"); 3024 return (NULL); 3025 } 3026 3027 nlp->nlp_jstat->js_start_ltime = time(NULL); 3028 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime; 3029 3030 nlp->nlp_logcallbacks = lbrlog_callbacks_init(session, 3031 ndmpd_path_restored_v3, NULL, NULL); 3032 if (!nlp->nlp_logcallbacks) { 3033 tlm_un_ref_job_stats(jname); 3034 free(jname); 3035 return (NULL); 3036 } 3037 nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks); 3038 3039 nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0); 3040 if (nlp->nlp_rsbm < 0) { 3041 NDMP_LOG(LOG_ERR, "Out of memory."); 3042 lbrlog_callbacks_done(nlp->nlp_logcallbacks); 3043 tlm_un_ref_job_stats(jname); 3044 free(jname); 3045 return (NULL); 3046 } 3047 3048 /* this is used in ndmpd_path_restored_v3() */ 3049 nlp->nlp_lastidx = -1; 3050 3051 NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).", 3052 ndmp_data_get_mover_mode(session)); 3053 3054 return (jname); 3055 } 3056 3057 /* 3058 * ndmpd_dar_tar_end_v3 3059 * 3060 * Deconstructor for the DAR restore. This function is called once per 3061 * DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3. 3062 * 3063 * Parameters: 3064 * session (input) - pointer to the session 3065 * params (input) - pointer to the parameters structure 3066 * nlp (input) - pointer to the nlp structure 3067 * jname(input) - job name 3068 * 3069 * Returns: 3070 * 0: on success 3071 * -1: on error 3072 */ 3073 static int ndmpd_dar_tar_end_v3(ndmpd_session_t *session, 3074 ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *jname) 3075 { 3076 int err = 0; 3077 3078 3079 NDMP_LOG(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx); 3080 3081 /* nothing restored. */ 3082 (void) send_unrecovered_list_v3(params, nlp); 3083 3084 if (nlp->nlp_jstat) { 3085 nlp->nlp_bytes_total = 3086 (u_longlong_t)nlp->nlp_jstat->js_bytes_total; 3087 tlm_un_ref_job_stats(jname); 3088 nlp->nlp_jstat = NULL; 3089 } else { 3090 NDMP_LOG(LOG_DEBUG, "JSTAT == NULL"); 3091 } 3092 3093 if (nlp->nlp_logcallbacks) { 3094 lbrlog_callbacks_done(nlp->nlp_logcallbacks); 3095 nlp->nlp_logcallbacks = NULL; 3096 } else { 3097 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL"); 3098 } 3099 3100 if (session->ns_data.dd_abort) { 3101 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.", 3102 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL"); 3103 err = EINTR; 3104 } else { 3105 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)", 3106 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : 3107 "NULL", err); 3108 } 3109 3110 if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) { 3111 if (nlp->nlp_rsbm < 0) { 3112 NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm); 3113 } else { 3114 (void) bm_free(nlp->nlp_rsbm); 3115 nlp->nlp_rsbm = -1; 3116 } 3117 } 3118 3119 free(jname); 3120 3121 return (err); 3122 } 3123 3124 3125 /* 3126 * ndmpd_dar_tar_v3 3127 * 3128 * This function is called for each entry in DAR entry list. The window 3129 * is already located and we should be in the right position to read 3130 * the data from the tape. 3131 * For each entry we setup selection list; so that, if the file name from 3132 * tape is not as the name client asked for, error be returned. 3133 * 3134 * Parameters: 3135 * session (input) - pointer to the session 3136 * params (input) - pointer to the parameters structure 3137 * nlp (input) - pointer to the nlp structure 3138 * jname (input) - job name 3139 * dar_index(input) - Index of this entry in the restore list 3140 * 3141 * Returns: 3142 * 0: on success 3143 * -1: on error 3144 */ 3145 static int 3146 ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 3147 ndmp_lbr_params_t *nlp, char *jname, int dar_index) 3148 { 3149 char *excl; 3150 char **sels; 3151 int flags; 3152 int err; 3153 tlm_commands_t *cmds; 3154 struct rs_name_maker rn; 3155 int data_addr_type = session->ns_data.dd_data_addr.addr_type; 3156 ndmp_tar_reader_arg_t arg; 3157 pthread_t rdtp; 3158 ndmp_context_t nctx; 3159 3160 err = 0; 3161 3162 /* 3163 * We have to allocate and deallocate buffers every time we 3164 * run the restore, for we need to flush the buffers. 3165 */ 3166 if (restore_dar_alloc_structs_v3(session, jname) < 0) 3167 return (-1); 3168 3169 sels = setupsels(session, params, nlp, dar_index); 3170 if (!sels) { 3171 free_dar_structs_v3(session, jname); 3172 return (-1); 3173 } 3174 excl = NULL; 3175 flags = RSFLG_OVR_ALWAYS; 3176 rn.rn_nlp = nlp; 3177 rn.rn_fp = mknewname; 3178 3179 if (!session->ns_data.dd_abort) { 3180 cmds = &nlp->nlp_cmds; 3181 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN; 3182 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN; 3183 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN; 3184 3185 arg.tr_session = session; 3186 arg.tr_mod_params = params; 3187 arg.tr_cmds = cmds; 3188 3189 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader, 3190 (void *)&arg); 3191 if (err == 0) { 3192 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER); 3193 } else { 3194 NDMP_LOG(LOG_DEBUG, "launch ndmp_tar_reader: %m"); 3195 return (-1); 3196 } 3197 3198 cmds->tcs_command->tc_ref++; 3199 cmds->tcs_writer_count++; 3200 3201 /* Plug-in module */ 3202 if (ndmp_pl != NULL && 3203 ndmp_pl->np_pre_restore != NULL) { 3204 nctx.nc_cmds = cmds; 3205 if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx, 3206 nlp->nlp_backup_path, nlp->nlp_restore_path)) 3207 != 0) { 3208 NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m"); 3209 cmds->tcs_command->tc_reader = TLM_STOP; 3210 ndmp_stop_local_reader(session, cmds); 3211 ndmp_wait_for_reader(cmds); 3212 (void) pthread_join(rdtp, NULL); 3213 ndmp_stop_remote_reader(session); 3214 goto restore_out; 3215 } 3216 } 3217 3218 if (tm_tar_ops.tm_getdir != NULL) { 3219 err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command, 3220 nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 3221 dar_index, session->hardlink_q); 3222 } 3223 3224 cmds->tcs_writer_count--; 3225 cmds->tcs_command->tc_ref--; 3226 cmds->tcs_command->tc_reader = TLM_STOP; 3227 3228 3229 /* 3230 * If it is a two-way restore then we stop the reader. 3231 */ 3232 NDMP_LOG(LOG_DEBUG, "stop local reader."); 3233 ndmp_stop_local_reader(session, cmds); 3234 3235 ndmp_wait_for_reader(cmds); 3236 (void) pthread_join(rdtp, NULL); 3237 3238 /* 3239 * If this is the last DAR entry and it is a three-way 3240 * restore then we should close the connection. 3241 */ 3242 if ((data_addr_type == NDMP_ADDR_TCP) && 3243 (dar_index == (int)session->ns_data.dd_nlist_len)) { 3244 NDMP_LOG(LOG_DEBUG, "stop remote reader."); 3245 ndmp_stop_remote_reader(session); 3246 } 3247 3248 /* exit as if there was an internal error */ 3249 if (session->ns_eof) 3250 err = -1; 3251 restore_out: 3252 /* Plug-in module */ 3253 if (ndmp_pl != NULL && 3254 ndmp_pl->np_post_restore != NULL && 3255 ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) { 3256 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m"); 3257 err = -1; 3258 } 3259 } 3260 3261 NDMP_FREE(sels); 3262 3263 free_dar_structs_v3(session, jname); 3264 3265 return (err); 3266 } 3267 3268 /* 3269 * ndmpd_dar_locate_windwos_v3 3270 * 3271 * Locating the right window in which the requested file is backed up. 3272 * We should go through windows to find the exact location, for the 3273 * file can be located in for example 10th window after the current window. 3274 * 3275 * Parameters: 3276 * session (input) - pointer to the session 3277 * params (input) - pointer to the parameters structure 3278 * fh_info (input) - index from the beginning of the backup stream 3279 * len (input) - Length of the mover window 3280 * 3281 * Returns: 3282 * 0: on success 3283 * -1: on error 3284 */ 3285 static int ndmpd_dar_locate_window_v3(ndmpd_session_t *session, 3286 ndmpd_module_params_t *params, u_longlong_t fh_info, long len) 3287 { 3288 int ret = 0; 3289 3290 3291 for (; ; ) { 3292 ret = (*params->mp_seek_func)(session, fh_info, len); 3293 3294 NDMP_LOG(LOG_DEBUG, "ret %d", ret); 3295 if (ret == 0) /* Seek was done successfully */ 3296 break; 3297 else if (ret < 0) { 3298 NDMP_LOG(LOG_DEBUG, "Seek error"); 3299 break; 3300 } 3301 3302 /* 3303 * DMA moved to a new window. 3304 * If we are reading the remainig of the file from 3305 * new window, seek is handled by ndmpd_local_read_v3. 3306 * Here we should continue the seek inside the new 3307 * window. 3308 */ 3309 continue; 3310 } 3311 return (ret); 3312 } 3313 3314 /* 3315 * ndmpd_rs_dar_tar_v3 3316 * 3317 * Main DAR function. It calls the constructor, then for each entry it 3318 * calls the locate_window_v3 to find the exact position of the file. Then 3319 * it restores the file. 3320 * When all restore requests are done it calls the deconstructor to clean 3321 * everything up. 3322 * 3323 * Parameters: 3324 * session (input) - pointer to the session 3325 * params (input) - pointer to the parameters structure 3326 * nlp (input) - pointer to the nlp structure 3327 * 3328 * Returns: 3329 * 0: on success 3330 * -1: on error 3331 */ 3332 static int 3333 ndmpd_rs_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 3334 ndmp_lbr_params_t *nlp) 3335 { 3336 mem_ndmp_name_v3_t *ep; 3337 u_longlong_t len; 3338 char *jname; 3339 int n = session->ns_data.dd_nlist_len; 3340 int i, ret = 0; 3341 int result = 0; 3342 3343 jname = ndmpd_dar_tar_init_v3(session, nlp); 3344 3345 if (!jname) 3346 return (-1); 3347 3348 /* 3349 * We set the length = sizeof (tlm_tar_hdr_t) 3350 * This is important for three-way DAR restore, for we should 3351 * read the header first (If we ask for more data then we have 3352 * to read and discard the remaining data in the socket) 3353 */ 3354 len = tlm_tarhdr_size(); 3355 3356 for (i = 0; i < n; ++i) { 3357 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i); 3358 if (!ep) { 3359 NDMP_LOG(LOG_DEBUG, "ep NULL, i %d", i); 3360 continue; 3361 } 3362 NDMP_LOG(LOG_DEBUG, 3363 "restoring opath %s, dpath %s, fh_info %lld", 3364 ep->nm3_opath ? ep->nm3_opath : "NULL", 3365 ep->nm3_dpath ? ep->nm3_dpath : "NULL", 3366 ep->nm3_fh_info); 3367 3368 /* 3369 * We should seek till finding the window in which file 3370 * is located. 3371 */ 3372 ret = ndmpd_dar_locate_window_v3(session, params, 3373 ep->nm3_fh_info, len); 3374 3375 if (ret < 0) /* If seek fails, restore should be aborted */ 3376 break; 3377 /* 3378 * We are inside the target window. 3379 * for each restore we will use one entry as selection list 3380 */ 3381 if ((ret = ndmpd_dar_tar_v3(session, params, nlp, jname, i+1)) 3382 != 0) 3383 result = EIO; 3384 ndmpd_audit_restore(session->ns_connection, 3385 ep->nm3_opath ? ep->nm3_opath : "NULL", 3386 session->ns_data.dd_data_addr.addr_type, 3387 session->ns_tape.td_adapter_name, result); 3388 } 3389 3390 NDMP_LOG(LOG_DEBUG, "End of restore list"); 3391 3392 (void) ndmpd_dar_tar_end_v3(session, params, nlp, jname); 3393 3394 return (ret); 3395 } 3396 3397 /* 3398 * ndmp_get_next_path 3399 * 3400 * Get the next path from a comma-separated path list 3401 */ 3402 static int 3403 ndmp_get_next_path(char **p, char *buf) 3404 { 3405 int len; 3406 3407 if (!*p || !**p) 3408 return (0); 3409 3410 while (isspace((unsigned char)**p)) 3411 (*p)++; 3412 len = strcspn(*p, ","); 3413 (void) strlcpy(buf, *p, len + 1); 3414 (*p) += len; 3415 if (**p == ',') 3416 (*p)++; 3417 return (len); 3418 } 3419 3420 /* 3421 * ndmp_plugin_pre_restore 3422 * 3423 * Wrapper for pre-restore callback with multiple path 3424 */ 3425 static int 3426 ndmp_plugin_pre_restore(ndmp_context_t *ctxp, char *orig_path, char *path) 3427 { 3428 char buf[PATH_MAX]; 3429 char *p = path; 3430 int err; 3431 3432 while (ndmp_get_next_path(&p, buf) != 0) { 3433 if ((err = ndmp_pl->np_pre_restore(ndmp_pl, ctxp, 3434 orig_path, buf)) != 0) 3435 return (err); 3436 } 3437 return (0); 3438 } 3439 3440 3441 /* 3442 * ndmpd_rs_sar_tar_v3 3443 * 3444 * Main non-DAR restore function. It will try to restore all the entries 3445 * that have been backed up. 3446 * 3447 * Parameters: 3448 * session (input) - pointer to the session 3449 * params (input) - pointer to the parameters structure 3450 * nlp (input) - pointer to the nlp structure 3451 * 3452 * Returns: 3453 * 0: on success 3454 * -1: on error 3455 */ 3456 static int 3457 ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params, 3458 ndmp_lbr_params_t *nlp) 3459 { 3460 char jname[TLM_MAX_BACKUP_JOB_NAME]; 3461 char *excl; 3462 char **sels; 3463 int flags; 3464 int err; 3465 tlm_commands_t *cmds; 3466 struct rs_name_maker rn; 3467 ndmp_tar_reader_arg_t arg; 3468 pthread_t rdtp; 3469 int result; 3470 ndmp_context_t nctx; 3471 3472 result = err = 0; 3473 (void) ndmp_new_job_name(jname); 3474 if (restore_alloc_structs_v3(session, jname) < 0) 3475 return (-1); 3476 3477 sels = setupsels(session, params, nlp, 0); 3478 if (!sels) { 3479 free_structs_v3(session, jname); 3480 return (-1); 3481 } 3482 excl = NULL; 3483 flags = RSFLG_OVR_ALWAYS; 3484 rn.rn_nlp = nlp; 3485 rn.rn_fp = mknewname; 3486 3487 nlp->nlp_jstat->js_start_ltime = time(NULL); 3488 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime; 3489 3490 if (!session->ns_data.dd_abort && !session->ns_data.dd_abort) { 3491 cmds = &nlp->nlp_cmds; 3492 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN; 3493 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN; 3494 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN; 3495 3496 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.", 3497 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL"); 3498 3499 arg.tr_session = session; 3500 arg.tr_mod_params = params; 3501 arg.tr_cmds = cmds; 3502 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader, 3503 (void *)&arg); 3504 if (err == 0) { 3505 tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER); 3506 } else { 3507 NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m"); 3508 free_structs_v3(session, jname); 3509 return (-1); 3510 } 3511 3512 if (!ndmp_check_utf8magic(cmds->tcs_command)) { 3513 NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!"); 3514 } else { 3515 NDMP_LOG(LOG_DEBUG, "UTF8Magic found"); 3516 } 3517 3518 /* Plug-in module */ 3519 if (ndmp_pl != NULL && 3520 ndmp_pl->np_pre_restore != NULL) { 3521 nctx.nc_cmds = cmds; 3522 if ((err = ndmp_plugin_pre_restore(&nctx, 3523 nlp->nlp_backup_path, nlp->nlp_restore_path)) 3524 != 0) { 3525 NDMP_LOG(LOG_DEBUG, "Pre-restore plug-in: %m"); 3526 cmds->tcs_command->tc_reader = TLM_STOP; 3527 ndmp_stop_local_reader(session, cmds); 3528 ndmp_wait_for_reader(cmds); 3529 (void) pthread_join(rdtp, NULL); 3530 ndmp_stop_remote_reader(session); 3531 goto restore_out; 3532 } 3533 } 3534 3535 cmds->tcs_command->tc_ref++; 3536 cmds->tcs_writer_count++; 3537 3538 if (tm_tar_ops.tm_getdir != NULL) 3539 err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command, 3540 nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 0, 3541 session->hardlink_q); 3542 3543 cmds->tcs_writer_count--; 3544 cmds->tcs_command->tc_ref--; 3545 cmds->tcs_command->tc_reader = TLM_STOP; 3546 nlp->nlp_jstat->js_stop_time = time(NULL); 3547 3548 /* Send the list of un-recovered files/dirs to the client. */ 3549 (void) send_unrecovered_list_v3(params, nlp); 3550 3551 ndmp_stop_local_reader(session, cmds); 3552 ndmp_wait_for_reader(cmds); 3553 (void) pthread_join(rdtp, NULL); 3554 3555 ndmp_stop_remote_reader(session); 3556 3557 /* exit as if there was an internal error */ 3558 if (session->ns_eof) 3559 err = -1; 3560 if (err == -1) 3561 result = EIO; 3562 } 3563 3564 (void) send_unrecovered_list_v3(params, nlp); /* nothing restored. */ 3565 if (session->ns_data.dd_abort) { 3566 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.", 3567 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL"); 3568 result = EINTR; 3569 ndmpd_audit_restore(session->ns_connection, 3570 nlp->nlp_restore_path, 3571 session->ns_data.dd_data_addr.addr_type, 3572 session->ns_tape.td_adapter_name, result); 3573 err = -1; 3574 } else { 3575 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)", 3576 (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL", 3577 err); 3578 ndmpd_audit_restore(session->ns_connection, 3579 nlp->nlp_restore_path, 3580 session->ns_data.dd_data_addr.addr_type, 3581 session->ns_tape.td_adapter_name, result); 3582 3583 restore_out: 3584 /* Plug-in module */ 3585 if (ndmp_pl != NULL && 3586 ndmp_pl->np_post_restore != NULL && 3587 ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) { 3588 NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m"); 3589 err = -1; 3590 } 3591 } 3592 3593 NDMP_FREE(sels); 3594 free_structs_v3(session, jname); 3595 3596 return (err); 3597 } 3598 3599 3600 /* 3601 * ndmp_backup_get_params_v3 3602 * 3603 * Get the backup parameters from the NDMP env variables 3604 * and log them in the system log and as normal messages 3605 * to the DMA. 3606 * 3607 * Parameters: 3608 * session (input) - pointer to the session 3609 * params (input) - pointer to the parameters structure 3610 * 3611 * Returns: 3612 * NDMP_NO_ERR: on success 3613 * != NDMP_NO_ERR: otherwise 3614 */ 3615 ndmp_error 3616 ndmp_backup_get_params_v3(ndmpd_session_t *session, 3617 ndmpd_module_params_t *params) 3618 { 3619 ndmp_error rv; 3620 ndmp_lbr_params_t *nlp; 3621 3622 if (!session || !params) 3623 return (NDMP_ILLEGAL_ARGS_ERR); 3624 3625 rv = NDMP_NO_ERR; 3626 nlp = ndmp_get_nlp(session); 3627 if (!nlp) { 3628 MOD_LOGV3(params, NDMP_LOG_ERROR, 3629 "Internal error: NULL nlp.\n"); 3630 rv = NDMP_ILLEGAL_ARGS_ERR; 3631 } else { 3632 if (!(nlp->nlp_backup_path = get_bk_path_v3(params))) 3633 rv = NDMP_FILE_NOT_FOUND_ERR; 3634 else if (!is_valid_backup_dir_v3(params, nlp->nlp_backup_path)) 3635 rv = NDMP_ILLEGAL_ARGS_ERR; 3636 } 3637 3638 if (rv != NDMP_NO_ERR) 3639 return (rv); 3640 3641 if (fs_is_chkpntvol(nlp->nlp_backup_path) || 3642 fs_is_rdonly(nlp->nlp_backup_path) || 3643 !fs_is_chkpnt_enabled(nlp->nlp_backup_path)) 3644 NLP_SET(nlp, NLPF_CHKPNTED_PATH); 3645 else 3646 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH); 3647 3648 /* Should the st_ctime be ignored when backing up? */ 3649 if (ndmp_ignore_ctime) { 3650 NDMP_LOG(LOG_DEBUG, "ignoring st_ctime"); 3651 NLP_SET(nlp, NLPF_IGNCTIME); 3652 } else { 3653 NLP_UNSET(nlp, NLPF_IGNCTIME); 3654 } 3655 3656 if (ndmp_include_lmtime == TRUE) { 3657 NDMP_LOG(LOG_DEBUG, "including st_lmtime"); 3658 NLP_SET(nlp, NLPF_INCLMTIME); 3659 } else { 3660 NLP_UNSET(nlp, NLPF_INCLMTIME); 3661 } 3662 3663 NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags); 3664 3665 get_hist_env_v3(params, nlp); 3666 get_exc_env_v3(params, nlp); 3667 get_inc_env_v3(params, nlp); 3668 get_direct_env_v3(params, nlp); 3669 rv = get_backup_level_v3(params, nlp); 3670 3671 return (rv); 3672 } 3673 3674 3675 /* 3676 * ndmpd_tar_backup_starter_v3 3677 * 3678 * Create the checkpoint for the backup and do the backup, 3679 * then remove the backup checkpoint if we created it. 3680 * Save the backup time information based on the backup 3681 * type and stop the data server. 3682 * 3683 * Parameters: 3684 * params (input) - pointer to the parameters structure 3685 * 3686 * Returns: 3687 * 0: on success 3688 * != 0: otherwise 3689 */ 3690 int 3691 ndmpd_tar_backup_starter_v3(ndmpd_module_params_t *params) 3692 { 3693 int err; 3694 ndmpd_session_t *session; 3695 ndmp_lbr_params_t *nlp; 3696 char jname[TLM_MAX_BACKUP_JOB_NAME]; 3697 3698 session = (ndmpd_session_t *)(params->mp_daemon_cookie); 3699 *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session); 3700 ndmp_session_ref(session); 3701 (void) ndmp_new_job_name(jname); 3702 3703 err = 0; 3704 if (!NLP_ISCHKPNTED(nlp) && 3705 ndmp_start_check_point(nlp->nlp_backup_path, jname) < 0) { 3706 MOD_LOGV3(params, NDMP_LOG_ERROR, 3707 "Creating checkpoint on \"%s\".\n", 3708 nlp->nlp_backup_path); 3709 err = -1; 3710 } 3711 3712 NDMP_LOG(LOG_DEBUG, "err %d, chkpnted %c", 3713 err, NDMP_YORN(NLP_ISCHKPNTED(nlp))); 3714 3715 /* Get an estimate of the data size */ 3716 get_backup_size(session, nlp->nlp_backup_path); 3717 3718 if (err == 0) { 3719 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, jname); 3720 if (err != 0) { 3721 NDMP_LOG(LOG_DEBUG, "err %d", err); 3722 } else { 3723 log_bk_params_v3(session, params, nlp); 3724 err = tar_backup_v3(session, params, nlp, jname); 3725 } 3726 } 3727 3728 if (!NLP_ISCHKPNTED(nlp)) 3729 (void) ndmp_release_check_point(nlp->nlp_backup_path, jname); 3730 3731 NDMP_LOG(LOG_DEBUG, "err %d, update %c", 3732 err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp))); 3733 3734 if (err == 0) 3735 save_backup_date_v3(params, nlp); 3736 3737 MOD_DONE(params, err); 3738 3739 /* nlp_params is allocated in start_backup_v3() */ 3740 NDMP_FREE(nlp->nlp_params); 3741 3742 NS_DEC(nbk); 3743 ndmp_session_unref(session); 3744 return (err); 3745 3746 } 3747 3748 3749 /* 3750 * ndmpd_tar_backup_abort_v3 3751 * 3752 * Abort the backup operation and stop the reader thread. 3753 * 3754 * Parameters: 3755 * module_cookie (input) - pointer to the nlp structure 3756 * 3757 * Returns: 3758 * 0: always 3759 */ 3760 int 3761 ndmpd_tar_backup_abort_v3(void *module_cookie) 3762 { 3763 ndmp_lbr_params_t *nlp; 3764 3765 nlp = (ndmp_lbr_params_t *)module_cookie; 3766 if (nlp && nlp->nlp_session) { 3767 if (nlp->nlp_session->ns_data.dd_data_addr.addr_type == 3768 NDMP_ADDR_TCP && 3769 nlp->nlp_session->ns_data.dd_sock != -1) { 3770 (void) close(nlp->nlp_session->ns_data.dd_sock); 3771 nlp->nlp_session->ns_data.dd_sock = -1; 3772 } 3773 ndmp_stop_reader_thread(nlp->nlp_session); 3774 } 3775 3776 return (0); 3777 } 3778 3779 3780 /* 3781 * ndmp_restore_get_params_v3 3782 * 3783 * Get the parameters specified for recovery such as restore path, type 3784 * of restore (DAR, non-DAR) etc 3785 * 3786 * Parameters: 3787 * session (input) - pointer to the session 3788 * params (input) - pointer to the parameters structure 3789 * 3790 * Returns: 3791 * NDMP_NO_ERR: on success 3792 * != NDMP_NO_ERR: otherwise 3793 */ 3794 ndmp_error 3795 ndmp_restore_get_params_v3(ndmpd_session_t *session, 3796 ndmpd_module_params_t *params) 3797 { 3798 ndmp_error rv; 3799 ndmp_lbr_params_t *nlp; 3800 3801 if (!(nlp = ndmp_get_nlp(session))) { 3802 NDMP_LOG(LOG_DEBUG, "nlp is NULL"); 3803 rv = NDMP_ILLEGAL_ARGS_ERR; 3804 } else if (!(nlp->nlp_backup_path = get_bk_path_v3(params))) 3805 rv = NDMP_ILLEGAL_ARGS_ERR; 3806 else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) { 3807 NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles); 3808 rv = NDMP_ILLEGAL_ARGS_ERR; 3809 } else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) { 3810 rv = NDMP_ILLEGAL_ARGS_ERR; 3811 } else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) { 3812 NDMP_LOG(LOG_DEBUG, "fix_nlist_v3: %d", rv); 3813 } else { 3814 rv = NDMP_NO_ERR; 3815 get_direct_env_v3(params, nlp); 3816 if (NLP_ISSET(nlp, NLPF_DIRECT)) { 3817 if (NLP_ISSET(nlp, NLPF_RECURSIVE)) { 3818 /* Currently we dont support DAR on directory */ 3819 NDMP_LOG(LOG_DEBUG, 3820 "Can't have RECURSIVE and DIRECT together"); 3821 rv = NDMP_ILLEGAL_ARGS_ERR; 3822 return (rv); 3823 } 3824 3825 /* 3826 * DAR can be done if all the fh_info's are valid. 3827 */ 3828 if (allvalidfh(session, params)) { 3829 ndmp_sort_nlist_v3(session); 3830 } else { 3831 MOD_LOGV3(params, NDMP_LOG_WARNING, 3832 "Cannot do direct access recovery. " 3833 "Some 'fh_info'es are not valid.\n"); 3834 NLP_UNSET(nlp, NLPF_DIRECT); 3835 } 3836 } 3837 3838 log_rs_params_v3(session, params, nlp); 3839 } 3840 3841 return (rv); 3842 } 3843 3844 3845 /* 3846 * ndmpd_tar_restore_starter_v3 3847 * 3848 * The main restore starter function. It will start a DAR or 3849 * non-DAR recovery based on the parameters. (V3 and V4 only) 3850 * 3851 * Parameters: 3852 * params (input) - pointer to the parameters structure 3853 * 3854 * Returns: 3855 * NDMP_NO_ERR: on success 3856 * != NDMP_NO_ERR: otherwise 3857 */ 3858 int 3859 ndmpd_tar_restore_starter_v3(ndmpd_module_params_t *params) 3860 { 3861 int err; 3862 ndmpd_session_t *session; 3863 ndmp_lbr_params_t *nlp; 3864 3865 3866 session = (ndmpd_session_t *)(params->mp_daemon_cookie); 3867 *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session); 3868 ndmp_session_ref(session); 3869 3870 if (NLP_ISSET(nlp, NLPF_DIRECT)) 3871 err = ndmpd_rs_dar_tar_v3(session, params, nlp); 3872 else 3873 err = ndmpd_rs_sar_tar_v3(session, params, nlp); 3874 3875 MOD_DONE(params, err); 3876 3877 NS_DEC(nrs); 3878 /* nlp_params is allocated in start_recover() */ 3879 NDMP_FREE(nlp->nlp_params); 3880 ndmp_session_unref(session); 3881 return (err); 3882 3883 } 3884 3885 3886 /* 3887 * ndmp_tar_restore_abort_v3 3888 * 3889 * Restore abort function (V3 and V4 only) 3890 * 3891 * Parameters: 3892 * module_cookie (input) - pointer to nlp 3893 * 3894 * Returns: 3895 * 0 3896 */ 3897 int 3898 ndmpd_tar_restore_abort_v3(void *module_cookie) 3899 { 3900 ndmp_lbr_params_t *nlp; 3901 3902 nlp = (ndmp_lbr_params_t *)module_cookie; 3903 if (nlp != NULL && nlp->nlp_session != NULL) { 3904 if (nlp->nlp_session->ns_data.dd_mover.addr_type == 3905 NDMP_ADDR_TCP && 3906 nlp->nlp_session->ns_data.dd_sock != -1) { 3907 (void) close(nlp->nlp_session->ns_data.dd_sock); 3908 nlp->nlp_session->ns_data.dd_sock = -1; 3909 } 3910 nlp_event_nw(nlp->nlp_session); 3911 ndmp_stop_writer_thread(nlp->nlp_session); 3912 } 3913 3914 3915 return (0); 3916 3917 } 3918