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