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