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