Print this page
NEX-15119 Commvault Certification fail incremental backup
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-15119 Commvault Certification fail incremental backup
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-13374 NDMP should be able to backup unmounted ZFS filesystems
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9532 NDMP: readdir errors when file/directory has special characters
Reviewed by: Peer Dampmann <peer.dampmann@nexenta.com>
Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Revert "NEX-5801 Snapshots left over after failed backups"
This reverts commit f182fb95f09036db71fbfc6f0a6b90469b761f21.
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-2911 NDMP logging should use syslog and is too chatty
SUP-898 nscd is extremely slow when a local file is missing
Reviewed by: Alek Pinchuk <alek.pinchuk@nexenta.com>
Reviewed by: Josef Sipek <josef.sipek@nexenta.com>
NEX-2500 Conflict between NDMP backup job and 'zfs send' leads to NDMP job abort.
NEX-2492 mdb loops forever printing a stack backtrace
NEX-2430 ndmpd segfaults in get_backup_size+0x13b() lint fix
NEX-2430 ndmpd segfaults in get_backup_size+0x13b()
NEX-559 NDMP cannot backup/restore a file which spans multiple tapes


  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 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
  41 
  42 #include <sys/stat.h>
  43 #include <sys/types.h>
  44 #include <sys/time.h>

  45 #include <ctype.h>
  46 #include <sys/socket.h>
  47 #include <sys/acl.h>
  48 #include <netinet/in.h>
  49 #include <arpa/inet.h>
  50 #include <errno.h>
  51 #include <stdio.h>
  52 #include <string.h>
  53 #include <time.h>
  54 #include <cstack.h>
  55 #include "ndmp.h"
  56 #include "ndmpd.h"
  57 #include <bitmap.h>
  58 #include <traverse.h>
  59 
  60 
  61 /*
  62  * Maximum length of the string-representation of u_longlong_t type.
  63  */
  64 #define QUAD_DECIMAL_LEN        20


  97 } bk_param_v3_t;
  98 
  99 
 100 /*
 101  * Multiple destination restore mode
 102  */
 103 #define MULTIPLE_DEST_DIRS 128
 104 
 105 int multiple_dest_restore = 0;
 106 
 107 /*
 108  * Plug-in module ops
 109  */
 110 ndmp_plugin_t *ndmp_pl;
 111 
 112 /*
 113  * NDMP exclusion list
 114  */
 115 char **ndmp_excl_list = NULL;
 116 


 117 /*
 118  * split_env
 119  *
 120  * Splits the string into list of sections separated by the
 121  * sep character.
 122  *
 123  * Parameters:
 124  *   envp (input) - the environment variable that should be broken
 125  *   sep (input) - the separator character
 126  *
 127  * Returns:
 128  *   Array of character pointers: On success.  The array is allocated
 129  *      as well as all its entries.  They all should be freed by the
 130  *      caller.
 131  *   NULL: on error
 132  */
 133 static char **
 134 split_env(char *envp, char sep)
 135 {
 136         char *bp, *cp, *ep;


 219         return (cpp);
 220 }
 221 
 222 
 223 /*
 224  * prl
 225  *
 226  * Print the array of character pointers passed to it.  This is
 227  * used for debugging purpose.
 228  *
 229  * Parameters:
 230  *   lpp (input) - pointer to the array of strings
 231  *
 232  * Returns:
 233  *   void
 234  */
 235 static void
 236 prl(char **lpp)
 237 {
 238         if (!lpp) {
 239                 NDMP_LOG(LOG_DEBUG, "empty");
 240                 return;
 241         }
 242 
 243         while (*lpp)
 244                 NDMP_LOG(LOG_DEBUG, "\"%s\"", *lpp++);
 245 }
 246 
 247 
 248 /*
 249  * inlist
 250  *
 251  * Looks through all the strings of the array to see if the ent
 252  * matches any of the strings.  The strings are patterns.
 253  *
 254  * Parameters:
 255  *   lpp (input) - pointer to the array of strings
 256  *   ent (input) - the entry to be matched
 257  *
 258  * Returns:
 259  *   TRUE: if there is a match
 260  *   FALSE: invalid argument or no match
 261  */
 262 static boolean_t
 263 inlist(char **lpp, char *ent)
 264 {
 265         if (!lpp || !ent) {
 266                 NDMP_LOG(LOG_DEBUG, "empty list");
 267                 return (FALSE);
 268         }
 269 
 270         while (*lpp) {
 271                 /*
 272                  * Fixing the sync_sort NDMPV3 problem, it sends the inclusion
 273                  * like "./" which we should skip the "./"
 274                  */
 275                 char *pattern = *lpp;
 276                 if (strncmp(pattern, "./", 2) == 0)
 277                         pattern += 2;
 278 
 279                 NDMP_LOG(LOG_DEBUG, "pattern %s, ent %s", pattern, ent);
 280 
 281                 if (match(pattern, ent)) {
 282                         NDMP_LOG(LOG_DEBUG, "match(%s,%s)", pattern, ent);
 283                         return (TRUE);
 284                 }
 285                 lpp++;
 286         }
 287 
 288         NDMP_LOG(LOG_DEBUG, "no match");
 289         return (FALSE);
 290 }
 291 
 292 
 293 /*
 294  * inexl
 295  *
 296  * Checks if the entry is in the list.  This is used for exclusion
 297  * list.  If the exclusion list is empty, FALSE should be returned
 298  * showing that nothing should be excluded by default.
 299  *
 300  * Parameters:
 301  *   lpp (input) - pointer to the array of strings
 302  *   ent (input) - the entry to be matched
 303  *
 304  * Returns:
 305  *   TRUE: if there is a match
 306  *   FALSE: invalid argument or no match
 307  *
 308  */


 394                 lpp += start; /* Next selection entry will be in lpp[start] */
 395         } else {
 396                 start = 0;
 397                 end = n;
 398         }
 399 
 400         for (i = start; i < end; i++) {
 401                 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
 402                 if (!ep)
 403                         continue;
 404 
 405                 /*
 406                  * Check for clients that send original path as "."(like
 407                  * CA products). In this situation opath is something like
 408                  * "/v1/." and we should change it to "/v1/"
 409                  */
 410                 len = strlen(ep->nm3_opath);
 411                 if (len > 1 && ep->nm3_opath[len-2] == '/' &&
 412                     ep->nm3_opath[len-1] == '.') {
 413                         ep->nm3_opath[len-1] = '\0';
 414                         NDMP_LOG(LOG_DEBUG,
 415                             "nm3_opath changed from %s. to %s",
 416                             ep->nm3_opath, ep->nm3_opath);
 417                 }
 418                 *lpp++ = ep->nm3_opath;
 419         }
 420 
 421         /* list termination indicator is a null pointer */
 422         *lpp = NULL;
 423 
 424         return (save);
 425 }
 426 
 427 
 428 /*
 429  * mkrsp
 430  *
 431  * Make Restore Path.
 432  * It gets a path, a selection (with which the path has matched) a new
 433  * name and makes a new name for the path.
 434  * All the components of the path and the selection are skipped as long


 469                 if (!COMPBNDRY(pp) || !COMPBNDRY(sp))
 470                         /* An exception to the boundary rule */
 471                         /* (!(!*sp && (*(pp - 1)) == '/')) */
 472                         if (*sp || (*(pp - 1)) != '/')
 473                                 return (NULL);
 474 
 475                 /* if pp shorter than sp, it should not be restored */
 476                 if (!*pp && *sp) {
 477                         sp += strspn(sp, "/");
 478                         if (strlen(sp) > 0)
 479                                 return (NULL);
 480                 }
 481         }
 482 
 483         if (np)
 484                 np += strspn(np, "/");
 485         else
 486                 np = "";
 487 
 488         if (!tlm_cat_path(bp, np, pp)) {
 489                 NDMP_LOG(LOG_ERR, "Restore path too long %s/%s.", np, pp);
 490                 return (NULL);
 491         }
 492 
 493         return (bp);
 494 }
 495 
 496 
 497 /*
 498  * mknewname
 499  *
 500  * This is used as callback for creating the restore path. This function
 501  * can handle both single destination and multiple restore paths.
 502  *
 503  * Make up the restore destination path for a particular file/directory, path,
 504  * based on nm3_opath and nm3_dpath.  path should have matched nm3_opath
 505  * in some way.
 506  */
 507 char *
 508 mknewname(struct rs_name_maker *rnp, char *buf, int idx, char *path)
 509 {
 510         char *rv;
 511         ndmp_lbr_params_t *nlp;
 512         mem_ndmp_name_v3_t *ep;
 513 
 514         rv = NULL;
 515         if (!buf) {
 516                 NDMP_LOG(LOG_DEBUG, "buf is NULL");
 517         } else if (!path) {
 518                 NDMP_LOG(LOG_DEBUG, "path is NULL");
 519         } else if ((nlp = rnp->rn_nlp) == 0) {
 520                 NDMP_LOG(LOG_DEBUG, "rnp->rn_nlp is NULL");
 521         } else if (!nlp->nlp_params) {
 522                 NDMP_LOG(LOG_DEBUG, "nlp->nlp_params is NULL");
 523         } else
 524                 if (!ndmp_full_restore_path) {
 525                         if (idx < 0 || idx >= (int)nlp->nlp_nfiles) {
 526                                 NDMP_LOG(LOG_DEBUG,
 527                                     "Invalid idx %d range (0, %d)",
 528                                     idx, nlp->nlp_nfiles);
 529                         } else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(
 530                             nlp->nlp_params, idx))) {
 531                                 NDMP_LOG(LOG_DEBUG,
 532                                     "nlist entry %d is NULL", idx);
 533                         } else {
 534                                 rv = mkrsp(buf, path, ep->nm3_opath,
 535                                     ep->nm3_dpath);
 536 
 537                                 NDMP_LOG(LOG_DEBUG,
 538                                     "idx %d org \"%s\" dst \"%s\"",
 539                                     idx, ep->nm3_opath, ep->nm3_dpath);
 540                                 if (rv) {
 541                                         NDMP_LOG(LOG_DEBUG,
 542                                             "path \"%s\": \"%s\"", path, rv);
 543                                 } else {
 544                                         NDMP_LOG(LOG_DEBUG,
 545                                             "path \"%s\": NULL", path);
 546                                 }
 547                         }
 548                 } else {
 549                         if (!tlm_cat_path(buf, nlp->nlp_restore_path, path)) {
 550                                 NDMP_LOG(LOG_ERR, "Path too long %s/%s.",
 551                                     nlp->nlp_restore_path, path);
 552                                 rv = NULL;
 553                         } else {
 554                                 rv = buf;
 555                                 NDMP_LOG(LOG_DEBUG,
 556                                     "path \"%s\": \"%s\"", path, rv);
 557                         }
 558                 }
 559 
 560         return (rv);
 561 }
 562 
 563 
 564 /*
 565  * chopslash
 566  *
 567  * Remove the slash from the end of the given path
 568  */
 569 static void
 570 chopslash(char *cp)
 571 {
 572         int ln;
 573 
 574         if (!cp || !*cp)
 575                 return;
 576 


 604         }
 605 
 606         return (bp);
 607 }
 608 
 609 
 610 /*
 611  * voliswr
 612  *
 613  * Is the volume writable?
 614  */
 615 static int
 616 voliswr(char *path)
 617 {
 618         int rv;
 619 
 620         if (!path)
 621                 return (0);
 622 
 623         rv = !fs_is_rdonly(path) && !fs_is_chkpntvol(path);
 624         NDMP_LOG(LOG_DEBUG, "%d path \"%s\"", rv, path);
 625         return (rv);
 626 
 627 }
 628 
 629 
 630 /*
 631  * is_valid_backup_dir_v3
 632  *
 633  * Checks the validity of the backup path.  Backup path should
 634  * have the following characteristics to be valid:
 635  *      1) It should be an absolute path.
 636  *      2) It should be a directory.
 637  *      3) It should not be checkpoint root directory
 638  *      4) If the file system is read-only, the backup path
 639  *          should be a checkpointed path.  Checkpoint cannot
 640  *          be created on a read-only file system.
 641  *
 642  * Parameters:
 643  *   params (input) - pointer to the parameters structure.
 644  *   bkpath (input) - the backup path


 773 /*
 774  * log_bk_params_v3
 775  *
 776  * Dispatcher function which calls the appropriate function
 777  * for logging the backup date and level in the system log
 778  * and also send them as normal log message to the client.
 779  *
 780  * Parameters:
 781  *   session (input) - pointer to the session
 782  *   params (input) - pointer to the parameters structure
 783  *   nlp (input) - pointer to the nlp structure
 784  *
 785  * Returns:
 786  *   void
 787  */
 788 static void
 789 log_bk_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
 790     ndmp_lbr_params_t *nlp)
 791 {
 792         MOD_LOGV3(params, NDMP_LOG_NORMAL, "Backing up \"%s\".\n",
 793             nlp->nlp_backup_path);
 794 
 795         if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_LOCAL)
 796                 MOD_LOGV3(params, NDMP_LOG_NORMAL,
 797                     "Tape record size: %d.\n",
 798                     session->ns_mover.md_record_size);
 799 
 800         MOD_LOGV3(params, NDMP_LOG_NORMAL, "File history: %c.\n",
 801             NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
 802 
 803         if (NLP_ISSET(nlp, NLPF_TOKENBK))
 804                 log_date_token_v3(params, nlp);
 805         else if (NLP_ISSET(nlp, NLPF_LBRBK))
 806                 log_lbr_bk_v3(params, nlp);
 807         else if (NLP_ISSET(nlp, NLPF_LEVELBK))
 808                 log_level_v3(params, nlp);
 809         else {
 810                 MOD_LOGV3(params, NDMP_LOG_ERROR,
 811                     "Internal error: backup level not defined for \"%s\".\n",
 812                     nlp->nlp_backup_path);
 813         }


 819  *
 820  * Is the UPDATE environment variable specified?  If it is
 821  * the corresponding flag is set in the flags field of the
 822  * nlp structure, otherwise the flag is cleared.
 823  *
 824  * Parameters:
 825  *   params (input) - pointer to the parameters structure
 826  *   nlp (input) - pointer to the nlp structure
 827  *
 828  * Returns:
 829  *   void
 830  */
 831 static void
 832 get_update_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 833 {
 834         char *envp;
 835 
 836         envp = MOD_GETENV(params, "UPDATE");
 837         if (!envp) {
 838                 NLP_SET(nlp, NLPF_UPDATE);
 839                 NDMP_LOG(LOG_DEBUG,
 840                     "env(UPDATE) not defined, default to TRUE");
 841         } else {
 842                 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", envp);
 843                 if (IS_YORT(*envp))
 844                         NLP_SET(nlp, NLPF_UPDATE);
 845                 else
 846                         NLP_UNSET(nlp, NLPF_UPDATE);
 847         }
 848 }
 849 
 850 
 851 /*
 852  * get_hist_env_v3
 853  *
 854  * Is backup history requested?  If it is, the corresponding
 855  * flag is set in the flags field of the nlp structure, otherwise
 856  * the flag is cleared.
 857  *
 858  * Parameters:
 859  *   params (input) - pointer to the parameters structure
 860  *   nlp (input) - pointer to the nlp structure
 861  *
 862  * Returns:
 863  *   void
 864  */
 865 static void
 866 get_hist_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 867 {
 868         char *envp;
 869 
 870         envp = MOD_GETENV(params, "HIST");
 871         if (!envp) {
 872                 NDMP_LOG(LOG_DEBUG, "env(HIST) not defined");
 873                 NLP_UNSET(nlp, NLPF_FH);
 874         } else {
 875                 NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", envp);
 876                 if (IS_YORT(*envp) || IS_F(*envp))
 877                         NLP_SET(nlp, NLPF_FH);
 878                 else
 879                         NLP_UNSET(nlp, NLPF_FH);
 880 
 881                 /* Force file format if specified */
 882                 if (IS_F(*envp)) {
 883                         params->mp_file_history_path_func =
 884                             ndmpd_api_file_history_file_v3;
 885                         params->mp_file_history_dir_func = 0;
 886                         params->mp_file_history_node_func = 0;
 887                 }
 888         }
 889 }
 890 
 891 
 892 /*
 893  * get_exc_env_v3
 894  *
 895  * Gets the EXCLUDE environment variable and breaks it
 896  * into strings.  The separator of the EXCLUDE environment
 897  * variable is the ',' character.
 898  *
 899  * Parameters:
 900  *   params (input) - pointer to the parameters structure
 901  *   nlp (input) - pointer to the nlp structure
 902  *
 903  * Returns:
 904  *   void
 905  */
 906 static void
 907 get_exc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 908 {
 909         char *envp;
 910 
 911         envp = MOD_GETENV(params, "EXCLUDE");
 912         if (!envp) {
 913                 NDMP_LOG(LOG_DEBUG, "env(EXCLUDE) not defined");
 914                 nlp->nlp_exl = NULL;
 915         } else {
 916                 NDMP_LOG(LOG_DEBUG, "env(EXCLUDE): \"%s\"", envp);
 917                 nlp->nlp_exl = split_env(envp, ',');
 918                 prl(nlp->nlp_exl);
 919         }
 920 }
 921 
 922 
 923 /*
 924  * get_inc_env_v3
 925  *
 926  * Gets the FILES environment variable that shows which files
 927  * should be backed up, and breaks it into strings.  The
 928  * separator of the FILES environment variable is the space
 929  * character.
 930  *
 931  * Parameters:
 932  *   params (input) - pointer to the parameters structure
 933  *   nlp (input) - pointer to the nlp structure
 934  *
 935  * Returns:
 936  *   void
 937  */
 938 static void
 939 get_inc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 940 {
 941         char *envp;
 942 
 943         envp = MOD_GETENV(params, "FILES");
 944         if (!envp) {
 945                 NDMP_LOG(LOG_DEBUG, "env(FILES) not defined");
 946                 nlp->nlp_inc = NULL;
 947         } else {
 948                 NDMP_LOG(LOG_DEBUG, "env(FILES): \"%s\"", envp);
 949                 nlp->nlp_inc = split_env(envp, ' ');
 950                 prl(nlp->nlp_inc);
 951         }
 952 }
 953 
 954 
 955 /*
 956  * get_direct_env_v3
 957  *
 958  * Gets the DIRECT environment variable that shows if the fh_info should
 959  * be sent to the client or not.
 960  *
 961  * Parameters:
 962  *   params (input) - pointer to the parameters structure
 963  *   nlp (input) - pointer to the nlp structure
 964  *
 965  * Returns:
 966  *   void
 967  */
 968 static void
 969 get_direct_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 970 {
 971         char *envp;
 972 
 973         /*
 974          * We should send the fh_info to the DMA, unless it is specified
 975          * in the request that we should not send fh_info.
 976          * At the moment we do not support DAR on directories, so if the user
 977          * needs to restore a directory they should disable the DAR.
 978          */
 979         if (params->mp_operation == NDMP_DATA_OP_RECOVER && !ndmp_dar_support) {
 980                 NDMP_LOG(LOG_DEBUG, "Direct Access Restore Disabled");
 981                 NLP_UNSET(nlp, NLPF_DIRECT);
 982                 MOD_LOGV3(params, NDMP_LOG_NORMAL,
 983                     "DAR is disabled. Running Restore without DAR");
 984                 return;
 985         }
 986 
 987         /*
 988          * Regardless of whether DIRECT is defined at backup time we send
 989          * back the fh_info, for some clients do not use get_backup_attrs.
 990          * If operation is restore we have to unset the DIRECT, for
 991          * some clients do not set the MOVER window.
 992          */
 993         if (params->mp_operation == NDMP_DATA_OP_BACKUP) {
 994                 NDMP_LOG(LOG_DEBUG, "backup default env(DIRECT): YES");
 995                 NLP_SET(nlp, NLPF_DIRECT);
 996         } else {
 997 
 998                 envp = MOD_GETENV(params, "DIRECT");
 999                 if (!envp) {
1000                         NDMP_LOG(LOG_DEBUG, "env(DIRECT) not defined");
1001                         NLP_UNSET(nlp, NLPF_DIRECT);
1002                 } else {
1003                         NDMP_LOG(LOG_DEBUG, "env(DIRECT): \"%s\"", envp);
1004                         if (IS_YORT(*envp)) {
1005                                 NLP_SET(nlp, NLPF_DIRECT);
1006                                 NDMP_LOG(LOG_DEBUG,
1007                                     "Direct Access Restore Enabled");
1008                         } else {
1009                                 NLP_UNSET(nlp, NLPF_DIRECT);
1010                                 NDMP_LOG(LOG_DEBUG,
1011                                     "Direct Access Restore Disabled");
1012                         }
1013                 }
1014         }
1015 
1016         if (NLP_ISSET(nlp, NLPF_DIRECT)) {
1017                 if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1018                         MOD_LOGV3(params, NDMP_LOG_NORMAL,
1019                             "Direct Access Restore information is supported");
1020                 else
1021                         MOD_LOGV3(params, NDMP_LOG_NORMAL,
1022                             "Running Restore with Direct Access Restore");
1023         } else {
1024                 if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1025                         MOD_LOGV3(params, NDMP_LOG_NORMAL,
1026                             "Direct Access Restore is not supported");
1027                 else
1028                         MOD_LOGV3(params, NDMP_LOG_NORMAL,
1029                             "Running Restore without Direct Access Restore");
1030         }


1070                 return (NDMP_ILLEGAL_ARGS_ERR);
1071 
1072         if (MOD_GETENV(params, "LEVEL")) {
1073                 MOD_LOGV3(params, NDMP_LOG_WARNING,
1074                     "Both BASE_DATE and LEVEL environment variables "
1075                     "defined.\n");
1076                 MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1077                     "BASE_DATE is being used for this backup.\n");
1078         }
1079 
1080         tok = strtoll(basedate, &endp, 10);
1081         if (endp == basedate) {
1082                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1083                     "Invalid BASE_DATE environment variable: \"%s\".\n",
1084                     basedate);
1085                 return (NDMP_ILLEGAL_ARGS_ERR);
1086         }
1087 
1088         tstamp = tok & 0xffffffff;
1089         seq = (tok >> 32) & 0xffffffff;
1090         NDMP_LOG(LOG_DEBUG, "basedate \"%s\" %lld seq %u tstamp %u",
1091             basedate, tok, seq, tstamp);
1092 
1093         if ((int)seq > ndmp_get_max_tok_seq()) {
1094                 rv = NDMP_ILLEGAL_ARGS_ERR;
1095                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1096                     "The sequence counter of the token exceeds the "
1097                     "maximum permitted value.\n");
1098                 MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1099                     "Token sequence: %u, maxiumum value: %u.\n",
1100                     seq, ndmp_get_max_tok_seq());
1101         } else if (seq >= NDMP_TOKSEQ_HLIMIT) {
1102                 rv = NDMP_ILLEGAL_ARGS_ERR;
1103                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1104                     "The sequence counter the of token exceeds the "
1105                     "hard-limit.\n");
1106                 MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1107                     "Token sequence: %u, hard-limit: %u.\n",
1108                     seq, NDMP_TOKSEQ_HLIMIT);
1109         } else {
1110                 rv = NDMP_NO_ERR;
1111                 /*


1211          * If the BASE_DATE env variable is specified use it, otherwise
1212          * look to see if LEVEL is specified.  If LEVEL is not
1213          * specified either, backup level '0' must be made. Level backup
1214          * does not clear the archive bit.
1215          *
1216          * If LEVEL environment varaible is specified, values for
1217          * 'F', 'D', 'I' and 'A' (for 'Full', 'Differential',
1218          * 'Incremental', and 'Archive' is checked first.  Then
1219          * level '0' to '9' will be checked.
1220          *
1221          * LEVEL environment variable can hold only one character.
1222          * If its length is longer than 1, an error is returned.
1223          */
1224         envp = MOD_GETENV(params, "BASE_DATE");
1225         if (envp)
1226                 return (get_date_token_v3(params, nlp, envp));
1227 
1228 
1229         envp = MOD_GETENV(params, "LEVEL");
1230         if (!envp) {
1231                 NDMP_LOG(LOG_DEBUG, "env(LEVEL) not defined, default to 0");
1232                 NLP_SET(nlp, NLPF_LEVELBK);
1233                 NLP_UNSET(nlp, NLPF_LBRBK);
1234                 NLP_UNSET(nlp, NLPF_TOKENBK);
1235                 nlp->nlp_llevel = 0;
1236                 nlp->nlp_ldate = 0;
1237                 nlp->nlp_clevel = 0;
1238                 /*
1239                  * The value of nlp_cdate will be set to the checkpoint
1240                  * creation time after it is created.
1241                  */
1242                 return (NDMP_NO_ERR);
1243         }
1244 
1245         if (*(envp+1) != '\0') {
1246                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1247                     "Invalid backup level \"%s\".\n", envp);
1248                 return (NDMP_ILLEGAL_ARGS_ERR);
1249         }
1250 
1251         if (IS_LBR_BKTYPE(*envp))


1293  * Parameters:
1294  *   params (input) - pointer to the parameters structure
1295  *   nlp (input) - pointer to the nlp structure
1296  *
1297  * Returns:
1298  *   void
1299  */
1300 static void
1301 save_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1302 {
1303         char val[QUAD_DECIMAL_LEN];
1304         u_longlong_t tok;
1305 
1306         if (!params || !nlp)
1307                 return;
1308 
1309         nlp->nlp_tokseq++;
1310         tok = ((u_longlong_t)nlp->nlp_tokseq << 32) | nlp->nlp_cdate;
1311         (void) snprintf(val, sizeof (val), "%llu", tok);
1312 
1313         NDMP_LOG(LOG_DEBUG, "tok: %lld %s", tok, val);
1314 
1315         if (MOD_SETENV(params, "DUMP_DATE", val) != 0) {
1316                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1317                     "Could not set DUMP_DATE to %s", val);
1318         } else if (!nlp->nlp_dmpnm) {
1319                 NDMP_LOG(LOG_DEBUG, "No log file defined");
1320         } else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1321             nlp->nlp_tokseq, nlp->nlp_tokdate) < 0) {
1322                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1323                     "Saving backup date for \"%s\" in \"%s\".\n",
1324                     nlp->nlp_backup_path, nlp->nlp_dmpnm);
1325         }
1326 }
1327 
1328 
1329 /*
1330  * save_lbr_bk_v3
1331  *
1332  * Append the backup type and date in the DMP_NAME file for
1333  * LBR-type backup if any file is specified.
1334  *
1335  * Parameters:
1336  *   params (input) - pointer to the parameters structure
1337  *   nlp (input) - pointer to the nlp structure
1338  *
1339  * Returns:
1340  *   void
1341  */
1342 static void
1343 save_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1344 {
1345         if (!params || !nlp)
1346                 return;
1347 
1348         if (!nlp->nlp_dmpnm) {
1349                 NDMP_LOG(LOG_DEBUG, "No log file defined");
1350         } else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1351             nlp->nlp_clevel, nlp->nlp_cdate) < 0) {
1352                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1353                     "Saving backup date for \"%s\" in \"%s\".\n",
1354                     nlp->nlp_backup_path, nlp->nlp_dmpnm);
1355         }
1356 }
1357 
1358 
1359 /*
1360  * save_level_v3
1361  *
1362  * Save the date and level of the current backup in the dumpdates
1363  * file.
1364  *
1365  * Parameters:
1366  *   params (input) - pointer to the parameters structure
1367  *   nlp (input) - pointer to the nlp structure
1368  *
1369  * Returns:
1370  *   void
1371  */
1372 static void
1373 save_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1374 {
1375         if (!params || !nlp)
1376                 return;
1377 
1378         if (!NLP_SHOULD_UPDATE(nlp)) {
1379                 NDMP_LOG(LOG_DEBUG, "update not requested");
1380         } else if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1381             nlp->nlp_cdate) < 0) {
1382                 MOD_LOGV3(params, NDMP_LOG_ERROR, "Logging backup date.\n");
1383         }
1384 }
1385 
1386 
1387 /*
1388  * save_backup_date_v3
1389  *
1390  * A dispatcher function to call the corresponding save function
1391  * based on the backup type.
1392  *
1393  * Parameters:
1394  *   params (input) - pointer to the parameters structure
1395  *   nlp (input) - pointer to the nlp structure
1396  *
1397  * Returns:
1398  *   void
1399  */


1410         else if (NLP_ISSET(nlp, NLPF_LEVELBK))
1411                 save_level_v3(params, nlp);
1412         else {
1413                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1414                     "Internal error: lost backup level type for \"%s\".\n",
1415                     nlp->nlp_backup_path);
1416         }
1417 }
1418 
1419 
1420 /*
1421  * backup_alloc_structs_v3
1422  *
1423  * Create the structures for V3 backup.  This includes:
1424  *      Job stats
1425  *      Reader writer IPC
1426  *      File history callback structure
1427  *
1428  * Parameters:
1429  *   session (input) - pointer to the session
1430  *   jname (input) - name assigned to the current backup for
1431  *      job stats strucure
1432  *
1433  * Returns:
1434  *   0: on success
1435  *   -1: otherwise
1436  */
1437 static int
1438 backup_alloc_structs_v3(ndmpd_session_t *session, char *jname)
1439 {
1440         int n;
1441         long xfer_size;
1442         ndmp_lbr_params_t *nlp;
1443         tlm_commands_t *cmds;
1444 
1445         nlp = ndmp_get_nlp(session);
1446         if (!nlp) {
1447                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1448                 return (-1);
1449         }
1450 
1451         nlp->nlp_jstat = tlm_new_job_stats(jname);
1452         if (!nlp->nlp_jstat) {
1453                 NDMP_LOG(LOG_DEBUG, "Creating job stats");
1454                 return (-1);
1455         }
1456 
1457         cmds = &nlp->nlp_cmds;
1458         (void) memset(cmds, 0, sizeof (*cmds));
1459 
1460         xfer_size = ndmp_buffer_get_size(session);
1461         if (xfer_size < 512*KILOBYTE) {
1462                 /*
1463                  * Read multiple of mover_record_size near to 512K.  This
1464                  * will prevent the data being copied in the mover buffer
1465                  * when we write the data.
1466                  */
1467                 n = 512 * KILOBYTE / xfer_size;
1468                 if (n <= 0)
1469                         n = 1;
1470                 xfer_size *= n;
1471                 NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d",
1472                     xfer_size);
1473         }
1474 
1475         cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
1476         if (!cmds->tcs_command) {
1477                 tlm_un_ref_job_stats(jname);
1478                 return (-1);
1479         }
1480 
1481         nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
1482             ndmpd_fhpath_v3_cb, ndmpd_fhdir_v3_cb, ndmpd_fhnode_v3_cb);
1483         if (!nlp->nlp_logcallbacks) {
1484                 tlm_release_reader_writer_ipc(cmds->tcs_command);
1485                 tlm_un_ref_job_stats(jname);
1486                 return (-1);
1487         }
1488         nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1489         nlp->nlp_restored = NULL;
1490 
1491         return (0);
1492 }
1493 
1494 
1495 /*
1496  * restore_alloc_structs_v3
1497  *
1498  * Create the structures for V3 Restore.  This includes:
1499  *      Job stats
1500  *      Reader writer IPC
1501  *      File recovery callback structure
1502  *
1503  * Parameters:
1504  *   session (input) - pointer to the session
1505  *   jname (input) - name assigned to the current backup for
1506  *      job stats strucure
1507  *
1508  * Returns:
1509  *   0: on success
1510  *   -1: otherwise
1511  */
1512 int
1513 restore_alloc_structs_v3(ndmpd_session_t *session, char *jname)
1514 {
1515         long xfer_size;
1516         ndmp_lbr_params_t *nlp;
1517         tlm_commands_t *cmds;
1518 
1519         nlp = ndmp_get_nlp(session);
1520         if (!nlp) {
1521                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1522                 return (-1);
1523         }
1524 
1525         /* this is used in ndmpd_path_restored_v3() */
1526         nlp->nlp_lastidx = -1;
1527 
1528         nlp->nlp_jstat = tlm_new_job_stats(jname);
1529         if (!nlp->nlp_jstat) {
1530                 NDMP_LOG(LOG_DEBUG, "Creating job stats");
1531                 return (-1);
1532         }
1533 
1534         cmds = &nlp->nlp_cmds;
1535         (void) memset(cmds, 0, sizeof (*cmds));
1536 
1537         xfer_size = ndmp_buffer_get_size(session);
1538         cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
1539         if (!cmds->tcs_command) {
1540                 tlm_un_ref_job_stats(jname);
1541                 return (-1);
1542         }
1543 
1544         nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
1545             ndmpd_path_restored_v3, NULL, NULL);
1546         if (!nlp->nlp_logcallbacks) {
1547                 tlm_release_reader_writer_ipc(cmds->tcs_command);
1548                 tlm_un_ref_job_stats(jname);
1549                 return (-1);
1550         }
1551         nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1552 
1553         nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
1554         if (nlp->nlp_rsbm < 0) {
1555                 NDMP_LOG(LOG_ERR, "Out of memory.");
1556                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1557                 tlm_release_reader_writer_ipc(cmds->tcs_command);
1558                 tlm_un_ref_job_stats(jname);
1559                 return (-1);
1560         }
1561 
1562         return (0);
1563 }
1564 
1565 
1566 /*
1567  * free_structs_v3
1568  *
1569  * Release the resources allocated by backup_alloc_structs_v3
1570  * function.
1571  *
1572  * Parameters:
1573  *   session (input) - pointer to the session
1574  *   jname (input) - name assigned to the current backup for
1575  *      job stats strucure
1576  *
1577  * Returns:
1578  *   void
1579  */
1580 /*ARGSUSED*/
1581 static void
1582 free_structs_v3(ndmpd_session_t *session, char *jname)
1583 {
1584         ndmp_lbr_params_t *nlp;
1585         tlm_commands_t *cmds;
1586 
1587         nlp = ndmp_get_nlp(session);
1588         if (!nlp) {
1589                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1590                 return;
1591         }
1592         cmds = &nlp->nlp_cmds;
1593         if (!cmds) {
1594                 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1595                 return;
1596         }
1597 
1598         if (nlp->nlp_logcallbacks) {
1599                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1600                 nlp->nlp_logcallbacks = NULL;
1601         } else
1602                 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
1603 
1604         if (cmds->tcs_command) {
1605                 if (cmds->tcs_command->tc_buffers != NULL)
1606                         tlm_release_reader_writer_ipc(cmds->tcs_command);
1607                 else
1608                         NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
1609                 cmds->tcs_command = NULL;
1610         } else
1611                 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
1612 
1613         if (nlp->nlp_bkmap >= 0) {
1614                 (void) dbm_free(nlp->nlp_bkmap);
1615                 nlp->nlp_bkmap = -1;
1616         }
1617 
1618         if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
1619                 if (nlp->nlp_rsbm < 0) {
1620                         NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
1621                 } else {
1622                         (void) bm_free(nlp->nlp_rsbm);
1623                         nlp->nlp_rsbm = -1;
1624                 }
1625         }
1626 }
1627 
1628 
1629 /*
1630  * backup_dirv3
1631  *
1632  * Backup a directory and update the bytes processed field of the
1633  * data server.
1634  *
1635  * Parameters:
1636  *   bpp (input) - pointer to the backup parameters structure
1637  *   pnp (input) - pointer to the path node
1638  *   enp (input) - pointer to the entry node
1639  *
1640  * Returns:
1641  *   0: on success
1642  *   != 0: otherwise
1643  */
1644 static int
1645 backup_dirv3(bk_param_v3_t *bpp, fst_node_t *pnp,
1646     fst_node_t *enp)
1647 {
1648         longlong_t apos, bpos;
1649         acl_t *aclp = NULL;
1650         char *acltp;
1651         struct stat64 st;
1652         char fullpath[TLM_MAX_PATH_NAME];
1653         char *p;
1654 
1655         if (!bpp || !pnp || !enp) {
1656                 NDMP_LOG(LOG_DEBUG, "Invalid argument");
1657                 return (-1);
1658         }
1659 
1660         NDMP_LOG(LOG_DEBUG, "d(%s)", bpp->bp_tmp);
1661 
1662         if (lstat64(bpp->bp_tmp, &st) != 0)
1663                 return (0);
1664 
1665         if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1666                 NDMP_LOG(LOG_DEBUG, "acl_get error errno=%d", errno);
1667                 return (-1);
1668         }
1669         if (aclp && (acltp = acl_totext(aclp,
1670             ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1671                 (void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
1672                     acltp, TLM_MAX_ACL_TXT);
1673                 acl_free(aclp);
1674                 free(acltp);
1675         } else {
1676                 *bpp->bp_tlmacl->acl_info.attr_info = '\0';
1677         }
1678 
1679         bpos = tlm_get_data_offset(bpp->bp_lcmd);
1680 
1681         p = bpp->bp_tmp + strlen(bpp->bp_chkpnm);
1682         if (*p == '/')
1683                 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
1684                     bpp->bp_unchkpnm, p);
1685         else
1686                 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",


1701 /*
1702  * backup_filev3
1703  *
1704  * Backup a file and update the bytes processed field of the
1705  * data server.
1706  *
1707  * Parameters:
1708  *   bpp (input) - pointer to the backup parameters structure
1709  *   pnp (input) - pointer to the path node
1710  *   enp (input) - pointer to the entry node
1711  *
1712  * Returns:
1713  *   0: on success
1714  *   != 0: otherwise
1715  */
1716 static int
1717 backup_filev3(bk_param_v3_t *bpp, fst_node_t *pnp,
1718     fst_node_t *enp)
1719 {
1720         char *ent;
1721         longlong_t rv;
1722         longlong_t apos, bpos;
1723         acl_t *aclp = NULL;
1724         char *acltp;
1725         struct stat64 st;
1726         char fullpath[TLM_MAX_PATH_NAME];
1727         char *p;
1728 
1729         if (!bpp || !pnp || !enp) {
1730                 NDMP_LOG(LOG_DEBUG, "Invalid argument");
1731                 return (-1);
1732         }
1733 
1734         NDMP_LOG(LOG_DEBUG, "f(%s)", bpp->bp_tmp);
1735 
1736         if (lstat64(bpp->bp_tmp, &st) != 0)
1737                 return (0);
1738 
1739         if (!S_ISLNK(bpp->bp_tlmacl->acl_attr.st_mode)) {
1740                 if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1741                         NDMP_LOG(LOG_DEBUG, "acl_get error");
1742                         return (-1);
1743                 }
1744 
1745                 if (aclp &&
1746                     (acltp = acl_totext(aclp,
1747                     ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1748                         (void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
1749                             acltp, TLM_MAX_ACL_TXT);
1750                         acl_free(aclp);
1751                         free(acltp);
1752                 } else {
1753                         *bpp->bp_tlmacl->acl_info.attr_info = '\0';
1754                 }
1755         }
1756 
1757         bpos = tlm_get_data_offset(bpp->bp_lcmd);
1758         ent = enp->tn_path ? enp->tn_path : "";
1759 
1760         p = pnp->tn_path + strlen(bpp->bp_chkpnm);
1761         if (*p == '/')


1786  *      - The bpp itself.
1787  *      - If the session pointer of the bpp is valid.
1788  *      - If the session connection to the DMA is closed.
1789  *      - If the nlp pointer of the bpp is valid.
1790  *      - If the backup is aborted.
1791  *
1792  * Parameters:
1793  *   bpp (input) - pointer to the backup parameters structure
1794  *
1795  * Returns:
1796  *   0: if everything's OK
1797  *   != 0: otherwise
1798  */
1799 static int
1800 check_bk_args(bk_param_v3_t *bpp)
1801 {
1802         int rv;
1803 
1804         if (!bpp) {
1805                 rv = -1;
1806                 NDMP_LOG(LOG_DEBUG, "Lost bpp");
1807         } else if (!bpp->bp_session) {
1808                 rv = -1;
1809                 NDMP_LOG(LOG_DEBUG, "Session is NULL");
1810         } else if (bpp->bp_session->ns_eof) {
1811                 rv = -1;
1812                 NDMP_LOG(LOG_INFO,
1813                     "Connection client is closed for backup \"%s\"",
1814                     bpp->bp_nlp->nlp_backup_path);
1815         } else if (!bpp->bp_nlp) {
1816                 NDMP_LOG(LOG_DEBUG, "Lost nlp");
1817                 return (-1);
1818         } else if (bpp->bp_session->ns_data.dd_abort) {
1819                 rv = -1;
1820                 NDMP_LOG(LOG_INFO, "Backup aborted \"%s\"",
1821                     bpp->bp_nlp->nlp_backup_path);
1822         } else
1823                 rv = 0;
1824 
1825         return (rv);
1826 }
1827 
1828 
1829 /*
1830  * shouldskip
1831  *
1832  * Determines if the current entry should be skipped or it
1833  * should be backed up.
1834  *
1835  * Parameters:
1836  *   bpp (input) - pointer to the backup parameters structure
1837  *   pnp (input) - pointer to the path node
1838  *   enp (input) - pointer to the entry node
1839  *   errp (output) - pointer to the error value that should be
1840  *      returned by the caller
1841  *
1842  * Returns:
1843  *   TRUE: if the entry should not be backed up
1844  *   FALSE: otherwise
1845  */
1846 static boolean_t
1847 shouldskip(bk_param_v3_t *bpp, fst_node_t *pnp,
1848     fst_node_t *enp, int *errp)
1849 {
1850         char *ent;
1851         boolean_t rv;
1852         struct stat64 *estp;
1853 
1854         if (!bpp || !pnp || !enp || !errp) {
1855                 NDMP_LOG(LOG_DEBUG, "Invalid argument");
1856                 return (TRUE);
1857         }
1858 
1859         if (!enp->tn_path) {
1860                 ent = "";
1861                 estp = pnp->tn_st;
1862         } else {
1863                 ent = enp->tn_path;
1864                 estp = enp->tn_st;
1865         }
1866 
1867         /*
1868          * When excluding or skipping entries, FST_SKIP should be
1869          * returned, otherwise, 0 should be returned to
1870          * get other entries in the directory of this entry.
1871          */
1872         if (!dbm_getone(bpp->bp_nlp->nlp_bkmap, (u_longlong_t)estp->st_ino)) {
1873                 rv = TRUE;
1874                 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1875                 NDMP_LOG(LOG_DEBUG, "Skipping %d %s/%s",
1876                     *errp, pnp->tn_path, ent);
1877         } else if (tlm_is_excluded(pnp->tn_path, ent, bpp->bp_excls)) {
1878                 rv = TRUE;
1879                 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1880                 NDMP_LOG(LOG_DEBUG, "excl %d \"%s/%s\"",
1881                     *errp, pnp->tn_path, ent);
1882         } else if (inexl(bpp->bp_nlp->nlp_exl, ent)) {
1883                 rv = TRUE;
1884                 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;
1885                 NDMP_LOG(LOG_DEBUG, "out %d \"%s/%s\"",
1886                     *errp, pnp->tn_path, ent);
1887         } else if (!S_ISDIR(estp->st_mode) &&
1888             !ininc(bpp->bp_nlp->nlp_inc, ent)) {
1889                 rv = TRUE;
1890                 *errp = 0;
1891                 NDMP_LOG(LOG_DEBUG, "!in \"%s/%s\"", pnp->tn_path, ent);
1892         } else
1893                 rv = FALSE;
1894 
1895         return (rv);
1896 }
1897 
1898 
1899 /*
1900  * ischngd
1901  *
1902  * Check if the object specified should be backed up or not.
1903  * If stp belongs to a directory and if it is marked in the
1904  * bitmap vector, it shows that either the directory itself is
1905  * modified or there is something below it that will be backed
1906  * up.
1907  *
1908  * By setting ndmp_force_bk_dirs global variable to a non-zero
1909  * value, directories are backed up anyways.
1910  *
1911  * Backing up the directories unconditionally helps
1912  * restoring the metadata of directories as well, when one
1913  * of the objects below them are being restored.
1914  *
1915  * For non-directory objects, if the modification or change
1916  * time of the object is after the date specified by the
1917  * bk_selector_t, the the object must be backed up.
1918  */
1919 static boolean_t
1920 ischngd(struct stat64 *stp, time_t t, ndmp_lbr_params_t *nlp)
1921 {
1922         boolean_t rv;
1923 
1924         if (!stp) {
1925                 rv = FALSE;
1926                 NDMP_LOG(LOG_DEBUG, "stp is NULL");
1927         } else if (!nlp) {
1928                 rv = FALSE;
1929                 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
1930         } else if (t == 0) {
1931                 /*
1932                  * if we are doing base backup then we do not need to
1933                  * check the time, for we should backup everything.
1934                  */
1935                 rv = TRUE;
1936                 NDMP_LOG(LOG_DEBUG, "Base Backup");
1937         } else if (S_ISDIR(stp->st_mode) && ndmp_force_bk_dirs) {
1938                 rv = TRUE;
1939                 NDMP_LOG(LOG_DEBUG, "d(%lu)", (uint_t)stp->st_ino);
1940         } else if (S_ISDIR(stp->st_mode) &&
1941             dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino) &&
1942             ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
1943             (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
1944                 /*
1945                  * If the object is a directory and it leads to a modified
1946                  * object (that should be backed up) and for that type of
1947                  * backup the path nodes should be backed up, then return
1948                  * TRUE.
1949                  *
1950                  * This is required by some DMAs like Backup Express, which
1951                  * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
1952                  * for the intermediate directories of a modified object.
1953                  * Other DMAs, like net_backup and net_worker, do not have such
1954                  * requirement.  This requirement makes sense for dump format
1955                  * but for 'tar' format, it does not.  In provision to the
1956                  * NDMP-v4 spec, for 'tar' format the intermediate directories
1957                  * need not to be reported.
1958                  */
1959                 rv = TRUE;
1960                 NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)stp->st_ino);
1961         } else if (stp->st_mtime > t) {
1962                 rv = TRUE;
1963                 NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu",
1964                     (uint_t)stp->st_ino, (uint_t)stp->st_mtime, (uint_t)t);
1965         } else if (stp->st_ctime > t) {
1966                 if (NLP_IGNCTIME(nlp)) {
1967                         rv = FALSE;
1968                         NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu",
1969                             (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
1970                             (uint_t)t);
1971                 } else {
1972                         rv = TRUE;
1973                         NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu",
1974                             (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
1975                             (uint_t)t);
1976                 }
1977         } else {
1978                 rv = FALSE;
1979                 NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
1980                     (uint_t)stp->st_ino, (uint_t)stp->st_mtime,
1981                     (uint_t)stp->st_ctime, (uint_t)t);
1982         }
1983 
1984         return (rv);
1985 }
1986 
1987 
1988 /*
1989  * iscreated
1990  *
1991  * This function is used to check last mtime (currently inside the ACL
1992  * structure) instead of ctime for checking if the file is to be backed up
1993  * or not. See option "inc.lmtime" for more details
1994  */
1995 /*ARGSUSED*/
1996 int iscreated(ndmp_lbr_params_t *nlp, char *name, tlm_acls_t *tacl,
1997     time_t t)
1998 {
1999         int ret;
2000         acl_t *aclp = NULL;
2001         char *acltp;
2002 
2003         NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
2004         if (NLP_INCLMTIME(nlp) == FALSE)
2005                 return (0);
2006 
2007         ret = acl_get(name, ACL_NO_TRIVIAL, &aclp);
2008         if (ret != 0) {
2009                 NDMP_LOG(LOG_DEBUG,
2010                     "Error getting the acl information: err %d", ret);
2011                 return (0);
2012         }
2013         if (aclp && (acltp = acl_totext(aclp,
2014             ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
2015                 (void) strlcpy(tacl->acl_info.attr_info, acltp,
2016                     TLM_MAX_ACL_TXT);
2017                 acl_free(aclp);
2018                 free(acltp);
2019         }
2020 
2021         /* Need to add support for last mtime */
2022 
2023         return (0);
2024 }
2025 
2026 /*
2027  * size_cb
2028  *
2029  * The callback function for calculating the size of


2075         rv = check_bk_args(bpp);
2076         if (rv != 0)
2077                 return (rv);
2078 
2079         stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2080         if (shouldskip(bpp, pnp, enp, &rv))
2081                 return (rv);
2082 
2083         if (enp->tn_path) {
2084                 ent = enp->tn_path;
2085                 stp = enp->tn_st;
2086                 fhp = enp->tn_fh;
2087         } else {
2088                 ent = "";
2089                 stp = pnp->tn_st;
2090                 fhp = pnp->tn_fh;
2091         }
2092 
2093 
2094         if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
2095                 NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
2096                 return (FST_SKIP);
2097         }
2098         if (NLP_ISSET(bpp->bp_nlp, NLPF_TOKENBK))
2099                 t = bpp->bp_nlp->nlp_tokdate;
2100         else if (NLP_ISSET(bpp->bp_nlp, NLPF_LEVELBK)) {
2101                 t = bpp->bp_nlp->nlp_ldate;
2102         } else {
2103                 NDMP_LOG(LOG_DEBUG, "Unknown backup type on \"%s/%s\"",
2104                     pnp->tn_path, ent);
2105                 return (-1);
2106         }
2107 
2108         if (S_ISDIR(stp->st_mode)) {
2109                 bpp->bp_tlmacl->acl_dir_fh = *fhp;
2110                 (void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
2111                     bpp->bp_tmp, stp);
2112 
2113                 if (ischngd(stp, t, bpp->bp_nlp)) {
2114                         (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2115                             sizeof (struct stat64));
2116                         rv = backup_dirv3(bpp, pnp, enp);
2117                 }
2118         } else {
2119                 if (ischngd(stp, t, bpp->bp_nlp) ||
2120                     iscreated(bpp->bp_nlp, bpp->bp_tmp, bpp->bp_tlmacl, t)) {
2121                         rv = 0;
2122                         (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2123                             sizeof (struct stat64));


2160         bpp = (bk_param_v3_t *)arg;
2161         rv = check_bk_args(bpp);
2162         if (rv != 0)
2163                 return (rv);
2164 
2165         stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2166         if (shouldskip(bpp, pnp, enp, &rv))
2167                 return (rv);
2168 
2169         if (enp->tn_path) {
2170                 ent = enp->tn_path;
2171                 stp = enp->tn_st;
2172                 fhp = enp->tn_fh;
2173         } else {
2174                 ent = "";
2175                 stp = pnp->tn_st;
2176                 fhp = pnp->tn_fh;
2177         }
2178 
2179         if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
2180                 NDMP_LOG(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
2181                 return (FST_SKIP);
2182         }
2183         if (!NLP_ISSET(bpp->bp_nlp, NLPF_LBRBK)) {
2184                 NDMP_LOG(LOG_DEBUG, "!NLPF_LBRBK");
2185                 return (-1);
2186         }
2187 
2188         if (S_ISDIR(stp->st_mode)) {
2189                 bpp->bp_tlmacl->acl_dir_fh = *fhp;
2190                 (void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
2191                     bpp->bp_tmp, stp);
2192 
2193                 if (SHOULD_LBRBK(bpp)) {
2194                         bpp->bp_tlmacl->acl_attr = *stp;
2195                         rv = backup_dirv3(bpp, pnp, enp);
2196                 }
2197         } else if (SHOULD_LBRBK(bpp)) {
2198                 rv = 0;
2199                 bpp->bp_tlmacl->acl_attr = *stp;
2200                 bpp->bp_tlmacl->acl_fil_fh = *fhp;
2201                 (void) backup_filev3(bpp, pnp, enp);
2202         }
2203 
2204         return (rv);
2205 }
2206 
2207 
2208 /*
2209  * backup_reader_v3
2210  *
2211  * The reader thread for the backup.  It sets up the callback
2212  * parameters and traverses the backup hierarchy in level-order
2213  * way.
2214  *
2215  * Parameters:
2216  *   jname (input) - name assigned to the current backup for
2217  *      job stats strucure
2218  *   nlp (input) - pointer to the nlp structure
2219  *   cmds (input) - pointer to the tlm_commands_t structure
2220  *
2221  * Returns:
2222  *   0: on success
2223  *   != 0: otherwise
2224  */
2225 static int
2226 backup_reader_v3(backup_reader_arg_t *argp)
2227 {
2228         int rv;
2229         tlm_cmd_t *lcmd;
2230         tlm_acls_t tlm_acls;
2231         longlong_t bpos, n;
2232         bk_param_v3_t bp;
2233         fs_traverse_t ft;
2234         char *jname;
2235         ndmp_lbr_params_t *nlp;
2236         tlm_commands_t *cmds;

2237 
2238         if (!argp)
2239                 return (-1);
2240 
2241         jname = argp->br_jname;
2242         nlp = argp->br_nlp;
2243         cmds = argp->br_cmds;
2244 
2245         rv = 0;
2246         lcmd = cmds->tcs_command;
2247         lcmd->tc_ref++;
2248         cmds->tcs_reader_count++;
2249 
2250         (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
2251 
2252         /* NDMP parameters */
2253         bp.bp_session = nlp->nlp_session;
2254         bp.bp_nlp = nlp;
2255 
2256         /* LBR-related parameters  */
2257         bp.bp_js = tlm_ref_job_stats(jname);
2258         bp.bp_cmds = cmds;
2259         bp.bp_lcmd = lcmd;
2260         bp.bp_tlmacl = &tlm_acls;
2261         bp.bp_opr = 0;
2262 
2263         /* release the parent thread, after referencing the job stats */
2264         (void) pthread_barrier_wait(&argp->br_barrier);



2265 
2266         bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2267         if (!bp.bp_tmp)
2268                 return (-1);
2269 
2270         /*
2271          * Make the checkpointed paths for traversing the
2272          * backup hierarchy, if we make the checkpoint.
2273          */
2274         bp.bp_unchkpnm = nlp->nlp_backup_path;
2275         if (!NLP_ISCHKPNTED(nlp)) {
2276                 tlm_acls.acl_checkpointed = TRUE;
2277                 bp.bp_chkpnm = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2278                 if (!bp.bp_chkpnm) {
2279                         NDMP_FREE(bp.bp_tmp);
2280                         return (-1);
2281                 }
2282                 (void) tlm_build_snapshot_name(nlp->nlp_backup_path,
2283                     bp.bp_chkpnm, nlp->nlp_jstat->js_job_name);
2284         } else {
2285                 tlm_acls.acl_checkpointed = FALSE;
2286                 bp.bp_chkpnm = nlp->nlp_backup_path;
2287         }
2288         bp.bp_excls = ndmpd_make_exc_list();
2289 
2290         /* set traversing arguments */
2291         ft.ft_path = nlp->nlp_backup_path;
2292         ft.ft_lpath = bp.bp_chkpnm;
2293 
2294         NDMP_LOG(LOG_DEBUG, "path %s lpath %s", ft.ft_path, ft.ft_lpath);
2295         if (NLP_ISSET(nlp, NLPF_TOKENBK) || NLP_ISSET(nlp, NLPF_LEVELBK)) {
2296                 ft.ft_callbk = timebk_v3;
2297                 tlm_acls.acl_clear_archive = FALSE;
2298         } else if (NLP_ISSET(nlp, NLPF_LBRBK)) {
2299                 ft.ft_callbk = lbrbk_v3;
2300                 tlm_acls.acl_clear_archive = FALSE;
2301 
2302                 NDMP_LOG(LOG_DEBUG, "bp_opr %x clr_arc %c",
2303                     bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive));
2304         } else {
2305                 rv = -1;
2306                 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2307                     "Unknow backup type.\n");
2308         }

2309         ft.ft_arg = &bp;
2310         ft.ft_logfp = (ft_log_t)ndmp_log;
2311         ft.ft_flags = FST_VERBOSE | FST_STOP_ONERR;
2312 


2313         /* take into account the header written to the stream so far */
2314         n = tlm_get_data_offset(lcmd);
2315         nlp->nlp_session->ns_data.dd_module.dm_stats.ms_bytes_processed = n;
2316 
2317         if (rv == 0) {
2318                 /* start traversing the hierarchy and actual backup */
2319                 rv = traverse_level(&ft);
2320                 if (rv == 0) {
2321                         /* write the trailer and update the bytes processed */
2322                         bpos = tlm_get_data_offset(lcmd);
2323                         (void) write_tar_eof(lcmd);
2324                         n = tlm_get_data_offset(lcmd) - bpos;
2325                         nlp->nlp_session->
2326                             ns_data.dd_module.dm_stats.ms_bytes_processed += n;
2327                 } else {
2328                         MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2329                             "Filesystem traverse error.\n");
2330                         ndmpd_data_error(nlp->nlp_session,
2331                             NDMP_DATA_HALT_INTERNAL_ERROR);
2332                 }
2333         }
2334 
2335         if (!NLP_ISCHKPNTED(nlp))
2336                 NDMP_FREE(bp.bp_chkpnm);
2337         NDMP_FREE(bp.bp_tmp);
2338         NDMP_FREE(bp.bp_excls);
2339 
2340         cmds->tcs_reader_count--;
2341         lcmd->tc_writer = TLM_STOP;
2342         tlm_release_reader_writer_ipc(lcmd);
2343         tlm_un_ref_job_stats(jname);
2344         return (rv);
2345 

2346 }
2347 
2348 
2349 /*
2350  * tar_backup_v3
2351  *
2352  * Traverse the backup hierarchy if needed and make the bitmap.
2353  * Then launch reader and writer threads to do the actual backup.
2354  *
2355  * Parameters:
2356  *   session (input) - pointer to the session
2357  *   params (input) - pointer to the parameters structure
2358  *   nlp (input) - pointer to the nlp structure
2359  *   jname (input) - job name
2360  *
2361  * Returns:
2362  *   0: on success
2363  *   != 0: otherwise
2364  */
2365 static int
2366 tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2367     ndmp_lbr_params_t *nlp, char *jname)
2368 {
2369         tlm_commands_t *cmds;
2370         backup_reader_arg_t arg;
2371         pthread_t rdtp;
2372         char info[256];
2373         int result;
2374         ndmp_context_t nctx;
2375         int err;

2376 
2377         if (ndmp_get_bk_dir_ino(nlp))

2378                 return (-1);

2379 
2380         result = err = 0;
2381 
2382         /* exit as if there was an internal error */
2383         if (session->ns_eof)
2384                 return (-1);
2385 
2386         if (!session->ns_data.dd_abort) {
2387                 if (backup_alloc_structs_v3(session, jname) < 0) {
2388                         nlp->nlp_bkmap = -1;
2389                         return (-1);
2390                 }
2391 
2392                 if (ndmpd_mark_inodes_v3(session, nlp) != 0) {
2393                         if (nlp->nlp_bkmap != -1) {
2394                                 (void) dbm_free(nlp->nlp_bkmap);
2395                                 nlp->nlp_bkmap = -1;
2396                         }
2397                         free_structs_v3(session, jname);
2398                         return (-1);
2399                 }
2400 
2401                 nlp->nlp_jstat->js_start_ltime = time(NULL);
2402                 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
2403                 nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
2404 
2405                 cmds = &nlp->nlp_cmds;
2406                 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
2407                 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
2408                 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
2409 
2410                 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
2411                         free_structs_v3(session, jname);
2412                         return (-1);
2413                 }
2414 
2415                 NDMP_LOG(LOG_DEBUG,
2416                     "Backing up \"%s\" started.", nlp->nlp_backup_path);

2417 
2418                 /* Plug-in module */
2419                 if (ndmp_pl != NULL &&
2420                     ndmp_pl->np_pre_backup != NULL) {
2421                         (void) memset(&nctx, 0, sizeof (ndmp_context_t));
2422                         nctx.nc_plversion = ndmp_pl->np_plversion;
2423                         nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
2424                         nctx.nc_cmds = cmds;
2425                         nctx.nc_params = params;
2426                         nctx.nc_ddata = (void *) session;
2427                         if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx,
2428                             nlp->nlp_backup_path)) != 0) {
2429                                 NDMP_LOG(LOG_ERR, "Pre-backup plug-in: %m");
2430                                 goto backup_out;
2431                         }
2432                 }
2433 
2434                 (void) memset(&arg, 0, sizeof (backup_reader_arg_t));
2435                 arg.br_jname = jname;
2436                 arg.br_nlp = nlp;
2437                 arg.br_cmds = cmds;
2438 
2439                 (void) pthread_barrier_init(&arg.br_barrier, 0, 2);
2440 
2441                 err = pthread_create(&rdtp, NULL, (funct_t)backup_reader_v3,
2442                     (void *)&arg);
2443                 if (err == 0) {
2444                         (void) pthread_barrier_wait(&arg.br_barrier);

2445                         (void) pthread_barrier_destroy(&arg.br_barrier);

2446                 } else {
2447                         (void) pthread_barrier_destroy(&arg.br_barrier);
2448                         free_structs_v3(session, jname);
2449                         NDMP_LOG(LOG_DEBUG, "Launch backup_reader_v3: %m");

2450                         return (-1);
2451                 }
2452 
2453                 if ((err = ndmp_tar_writer(session, params, cmds)) != 0)
2454                         result = EIO;
2455 
2456                 nlp->nlp_jstat->js_stop_time = time(NULL);
2457 
2458                 (void) snprintf(info, sizeof (info),
2459                     "Runtime [%s] %llu bytes (%llu): %d seconds\n",
2460                     nlp->nlp_backup_path,
2461                     session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2462                     session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2463                     nlp->nlp_jstat->js_stop_time -
2464                     nlp->nlp_jstat->js_start_ltime);
2465                 MOD_LOGV3(params, NDMP_LOG_NORMAL, info);
2466 
2467                 ndmp_wait_for_reader(cmds);
2468                 (void) pthread_join(rdtp, NULL);
2469 
2470                 /* exit as if there was an internal error */
2471                 if (session->ns_eof) {
2472                         result = EPIPE;
2473                         err = -1;
2474                 }
2475                 if (!session->ns_data.dd_abort) {
2476                         ndmpd_audit_backup(session->ns_connection,
2477                             nlp->nlp_backup_path,
2478                             session->ns_data.dd_data_addr.addr_type,
2479                             session->ns_tape.td_adapter_name, result);
2480                         NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" Finished.",
2481                             nlp->nlp_backup_path);

2482                 }
2483         }
2484 
2485         if (session->ns_data.dd_abort) {
2486                 ndmpd_audit_backup(session->ns_connection,
2487                     nlp->nlp_backup_path,
2488                     session->ns_data.dd_data_addr.addr_type,
2489                     session->ns_tape.td_adapter_name, EINTR);
2490                 NDMP_LOG(LOG_DEBUG,
2491                     "Backing up \"%s\" aborted.", nlp->nlp_backup_path);

2492                 err = -1;
2493         } else {
2494 
2495 backup_out:
2496                 /* Plug-in module */
2497                 if (ndmp_pl != NULL &&
2498                     ndmp_pl->np_post_backup != NULL &&
2499                     ndmp_pl->np_post_backup(ndmp_pl, &nctx, err) == -1) {
2500                         NDMP_LOG(LOG_DEBUG, "Post-backup plug-in: %m");
2501                         return (-1);
2502                 }
2503         }
2504 
2505         free_structs_v3(session, jname);
2506         return (err);
2507 }
2508 
2509 /*
2510  * get_backup_size
2511  *
2512  * Find the estimate of backup size. This is used to get an estimate
2513  * of the progress of backup during NDMP backup.
2514  */
2515 void
2516 get_backup_size(ndmp_bkup_size_arg_t *sarg)
2517 {
2518         fs_traverse_t ft;
2519         u_longlong_t bk_size;

2520         char spath[PATH_MAX];
2521         int rv;
2522 
2523         bk_size = 0;
2524         if (fs_is_chkpntvol(sarg->bs_path)) {
2525                 ft.ft_path = sarg->bs_path;
2526         } else {
2527                 (void) tlm_build_snapshot_name(sarg->bs_path,
2528                     spath, sarg->bs_jname);
2529                 ft.ft_path = spath;
2530         }
2531 
2532         ft.ft_lpath = ft.ft_path;
2533         ft.ft_callbk = size_cb;
2534         ft.ft_arg = &bk_size;
2535         ft.ft_logfp = (ft_log_t)ndmp_log;
2536         ft.ft_flags = FST_VERBOSE;
2537 
2538         if ((rv = traverse_level(&ft)) != 0) {
2539                 NDMP_LOG(LOG_DEBUG, "bksize err=%d", rv);


2540                 bk_size = 0;
2541         } else {
2542                 NDMP_LOG(LOG_DEBUG, "bksize %lld, %lldKB, %lldMB\n",
2543                     bk_size, bk_size / 1024, bk_size /(1024 * 1024));

2544         }
2545         sarg->bs_session->ns_data.dd_data_size = bk_size;

2546 }
2547 
2548 /*
2549  * get_rs_path_v3
2550  *
2551  * Find the restore path
2552  */
2553 ndmp_error
2554 get_rs_path_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2555 {
2556         char *dp;
2557         ndmp_error rv;
2558         mem_ndmp_name_v3_t *ep;
2559         int i, nm_cnt;
2560         char *nm_dpath_list[MULTIPLE_DEST_DIRS];
2561         static char mdest_buf[256];
2562 
2563         *mdest_buf = 0;
2564         *nm_dpath_list = "";
2565         for (i = 0, nm_cnt = 0; i < (int)nlp->nlp_nfiles; i++) {
2566                 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2567                 if (!ep) {
2568                         NDMP_LOG(LOG_DEBUG, "Can't get Nlist[%d]", i);
2569                         return (NDMP_ILLEGAL_ARGS_ERR);
2570                 }
2571                 if (strcmp(nm_dpath_list[nm_cnt], ep->nm3_dpath) != 0 &&
2572                     nm_cnt < MULTIPLE_DEST_DIRS - 1)
2573                         nm_dpath_list[++nm_cnt] = ep->nm3_dpath;
2574         }
2575 
2576         multiple_dest_restore = (nm_cnt > 1);
2577         nlp->nlp_restore_path = mdest_buf;
2578 
2579         for (i = 1; i < nm_cnt + 1; i++) {
2580                 if (ISDEFINED(nm_dpath_list[i]))
2581                         dp = nm_dpath_list[i];
2582                 else
2583                         /* the default destination path is backup directory */
2584                         dp = nlp->nlp_backup_path;
2585 
2586                 /* check the destination directory exists and is writable */
2587                 if (!fs_volexist(dp)) {
2588                         rv = NDMP_ILLEGAL_ARGS_ERR;
2589                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2590                             "Invalid destination path volume \"%s\".\n", dp);
2591                 } else if (!voliswr(dp)) {
2592                         rv = NDMP_ILLEGAL_ARGS_ERR;
2593                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2594                             "The destination path volume"
2595                             " is not writable \"%s\".\n", dp);
2596                 } else {
2597                         rv = NDMP_NO_ERR;
2598                         (void) strlcat(nlp->nlp_restore_path, dp,
2599                             sizeof (mdest_buf));
2600                         NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", dp);
2601                 }
2602 
2603                 /*
2604                  * Exit if there is an error or it is not a multiple
2605                  * destination restore mode
2606                  */
2607                 if (rv != NDMP_NO_ERR || !multiple_dest_restore)
2608                         break;
2609 
2610                 if (i < nm_cnt)
2611                         (void) strlcat(nlp->nlp_restore_path, ", ",
2612                             sizeof (mdest_buf));
2613         }
2614 
2615         return (rv);
2616 }
2617 
2618 
2619 /*
2620  * fix_nlist_v3


2750                 bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath);
2751                 if (!bp) {
2752                         /*
2753                          * Note: The same problem of above with long path.
2754                          */
2755                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2756                             "Path too long(%s/%s)",
2757                             nlp->nlp_backup_path, ep->nm3_opath);
2758                         continue;
2759                 }
2760                 cp = strdup(bp);
2761                 if (!cp) {
2762                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2763                             "Insufficient memory.\n");
2764                         rv = NDMP_NO_MEM_ERR;
2765                         break;
2766                 }
2767                 NDMP_FREE(ep->nm3_opath);
2768                 ep->nm3_opath = cp;
2769 
2770                 NDMP_LOG(LOG_DEBUG, "orig[%d]: \"%s\"", i, ep->nm3_opath);
2771                 if (ep->nm3_dpath) {
2772                         NDMP_LOG(LOG_DEBUG,
2773                             "dest[%d]: \"%s\"", i, ep->nm3_dpath);
2774                 } else {
2775                         NDMP_LOG(LOG_DEBUG, "dest[%d]: \"%s\"", i, "NULL");
2776                 }
2777         }
2778 
2779         free(buf);
2780 
2781         return (rv);
2782 }
2783 
2784 
2785 /*
2786  * allvalidfh
2787  *
2788  * Run a sanity check on the file history info. The file history
2789  * info is the offset of the record starting the entry on the tape
2790  * and is used in DAR (direct access restore mode).
2791  */
2792 static boolean_t
2793 allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params)
2794 {
2795         int i, n;


2850 
2851         if (NLP_ISSET(nlp, NLPF_DIRECT))
2852                 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2853                     "Direct Access Restore.\n");
2854 }
2855 
2856 
2857 /*
2858  * send_unrecovered_list_v3
2859  *
2860  * Create the list of files that were in restore list but
2861  * not recovered due to some errors.
2862  */
2863 int
2864 send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2865 {
2866         int i, rv;
2867         int err;
2868 
2869         if (!params) {
2870                 NDMP_LOG(LOG_DEBUG, "params == NULL");
2871                 return (-1);
2872         }
2873         if (!nlp) {
2874                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2875                 return (-1);
2876         }
2877 
2878         if (nlp->nlp_lastidx != -1) {
2879                 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)nlp->nlp_lastidx))
2880                         err = ENOENT;
2881                 else
2882                         err = 0;
2883                 (void) ndmp_send_recovery_stat_v3(params, nlp,
2884                     nlp->nlp_lastidx, err);
2885                 nlp->nlp_lastidx = -1;
2886         }
2887 
2888         rv = 0;
2889         for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
2890                 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)i)) {
2891                         rv = ndmp_send_recovery_stat_v3(params, nlp, i, ENOENT);
2892                         if (rv < 0)
2893                                 break;
2894                 }
2895         }
2896 
2897         return (rv);
2898 }
2899 
2900 
2901 
2902 /*
2903  * restore_dar_alloc_structs_v3
2904  *
2905  * Allocates the necessary structures for running DAR restore.
2906  * It just creates the reader writer IPC.
2907  * This function is called for each entry in the restore entry list.
2908  *
2909  * Parameters:
2910  *   session (input) - pointer to the session
2911  *   jname (input) - Job name
2912  *
2913  * Returns:
2914  *    0: on success
2915  *   -1: on error
2916  */
2917 int
2918 restore_dar_alloc_structs_v3(ndmpd_session_t *session, char *jname)
2919 {
2920         long xfer_size;
2921         ndmp_lbr_params_t *nlp;
2922         tlm_commands_t *cmds;
2923 
2924         nlp = ndmp_get_nlp(session);
2925         if (!nlp) {
2926                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2927                 return (-1);
2928         }
2929 
2930         cmds = &nlp->nlp_cmds;
2931         (void) memset(cmds, 0, sizeof (*cmds));
2932 
2933         xfer_size = ndmp_buffer_get_size(session);
2934         cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2935         if (!cmds->tcs_command) {
2936                 tlm_un_ref_job_stats(jname);
2937                 return (-1);
2938         }
2939 
2940         return (0);
2941 }
2942 
2943 
2944 /*
2945  * free_dar_structs_v3
2946  *
2947  * To free the structures were created by restore_dar_alloc_structs_v3.
2948  * This funnction is called for each entry in restore entry list.
2949  *
2950  * Parameters:
2951  *   session (input) - pointer to the session
2952  *   jname (input) - job name
2953  *
2954  * Returns:
2955  *      NONE
2956  */
2957 /*ARGSUSED*/
2958 static void
2959 free_dar_structs_v3(ndmpd_session_t *session, char *jname)
2960 {
2961         ndmp_lbr_params_t *nlp;
2962         tlm_commands_t *cmds;
2963 
2964         nlp = ndmp_get_nlp(session);
2965         if (!nlp) {
2966                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
2967                 return;
2968         }
2969         cmds = &nlp->nlp_cmds;
2970         if (!cmds) {
2971                 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
2972                 return;
2973         }
2974 
2975         if (cmds->tcs_command) {
2976                 if (cmds->tcs_command->tc_buffers != NULL)
2977                         tlm_release_reader_writer_ipc(cmds->tcs_command);
2978                 else
2979                         NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
2980                 cmds->tcs_command = NULL;
2981         } else
2982                 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
2983 }
2984 
2985 
2986 /*
2987  * ndmp_dar_tar_init_v3
2988  *
2989  * Constructor for the DAR restore. Creates job name, allocates structures
2990  * needed for keeping the statistics, and reports the start of restore action.
2991  * It is called once for each DAR restore request.
2992  *
2993  * Parameters:
2994  *   session (input) - pointer to the session
2995  *   nlp (input) - pointer to the nlp structure
2996  *
2997  * Returns:
2998  *   char pointer: on success
2999  *   NULL: on error
3000  */
3001 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session,
3002     ndmp_lbr_params_t *nlp)
3003 {
3004         char *jname;
3005 
3006         jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME);
3007 
3008         if (!jname)
3009                 return (NULL);
3010 
3011         (void) ndmp_new_job_name(jname);



3012 
3013         if (!nlp) {
3014                 free(jname);
3015                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
3016                 return (NULL);
3017         }
3018 
3019         nlp->nlp_jstat = tlm_new_job_stats(jname);
3020         if (!nlp->nlp_jstat) {
3021                 free(jname);
3022                 NDMP_LOG(LOG_DEBUG, "Creating job stats");
3023                 return (NULL);
3024         }
3025 
3026         nlp->nlp_jstat->js_start_ltime = time(NULL);
3027         nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3028 
3029         nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
3030             ndmpd_path_restored_v3, NULL, NULL);
3031         if (!nlp->nlp_logcallbacks) {
3032                 tlm_un_ref_job_stats(jname);
3033                 free(jname);
3034                 return (NULL);
3035         }
3036         nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
3037 
3038         nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
3039         if (nlp->nlp_rsbm < 0) {
3040                 NDMP_LOG(LOG_ERR, "Out of memory.");
3041                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3042                 tlm_un_ref_job_stats(jname);
3043                 free(jname);
3044                 return (NULL);
3045         }
3046 
3047         /* this is used in ndmpd_path_restored_v3() */
3048         nlp->nlp_lastidx = -1;
3049 
3050         NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).",
3051             ndmp_data_get_mover_mode(session));
3052 
3053         return (jname);
3054 }
3055 
3056 /*
3057  * ndmpd_dar_tar_end_v3
3058  *
3059  * Deconstructor for the DAR restore. This function is called once per
3060  * DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3.
3061  *
3062  * Parameters:
3063  *   session (input) - pointer to the session
3064  *   params (input) - pointer to the parameters structure
3065  *   nlp (input) - pointer to the nlp structure
3066  *   jname(input) - job name
3067  *
3068  * Returns:
3069  *   0: on success
3070  *   -1: on error
3071  */
3072 static int ndmpd_dar_tar_end_v3(ndmpd_session_t *session,
3073     ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *jname)
3074 {
3075         int err = 0;
3076 
3077 
3078         NDMP_LOG(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx);
3079 
3080         /* nothing restored. */
3081         (void) send_unrecovered_list_v3(params, nlp);
3082 
3083         if (nlp->nlp_jstat) {
3084                 nlp->nlp_bytes_total =
3085                     (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
3086                 tlm_un_ref_job_stats(jname);
3087                 nlp->nlp_jstat = NULL;
3088         } else {
3089                 NDMP_LOG(LOG_DEBUG, "JSTAT == NULL");
3090         }
3091 
3092         if (nlp->nlp_logcallbacks) {
3093                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3094                 nlp->nlp_logcallbacks = NULL;
3095         } else {
3096                 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
3097         }
3098 
3099         if (session->ns_data.dd_abort) {
3100                 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3101                     (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3102                 err = EINTR;
3103         } else {
3104                 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3105                     (nlp->nlp_restore_path) ? nlp->nlp_restore_path :
3106                     "NULL", err);
3107         }
3108 
3109         if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
3110                 if (nlp->nlp_rsbm < 0) {
3111                         NDMP_LOG(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
3112                 } else {
3113                         (void) bm_free(nlp->nlp_rsbm);
3114                         nlp->nlp_rsbm = -1;
3115                 }
3116         }
3117 
3118         free(jname);
3119 
3120         return (err);
3121 }
3122 
3123 
3124 /*
3125  * ndmpd_dar_tar_v3
3126  *
3127  * This function is called for each entry in DAR entry list. The window
3128  * is already located and we should be in the right position to read
3129  * the data from the tape.
3130  * For each entry we setup selection list; so that, if the file name from
3131  * tape is not as the name client asked for, error be returned.
3132  *
3133  * Parameters:
3134  *   session (input) - pointer to the session
3135  *   params (input) - pointer to the parameters structure
3136  *   nlp (input) - pointer to the nlp structure
3137  *   jname (input) - job name
3138  *   dar_index(input) - Index of this entry in the restore list
3139  *
3140  * Returns:
3141  *   0: on success
3142  *   -1: on error
3143  */
3144 static int
3145 ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3146     ndmp_lbr_params_t *nlp, char *jname, int dar_index)
3147 {
3148         char *excl;
3149         char **sels;
3150         int flags;
3151         int err;
3152         tlm_commands_t *cmds;
3153         struct rs_name_maker rn;
3154         int data_addr_type = session->ns_data.dd_data_addr.addr_type;
3155         ndmp_tar_reader_arg_t arg;
3156         pthread_t rdtp;
3157         ndmp_context_t nctx;
3158         mem_ndmp_name_v3_t *ep;
3159 
3160         err = 0;
3161 
3162         /*
3163          * We have to allocate and deallocate buffers every time we
3164          * run the restore, for we need to flush the buffers.
3165          */
3166         if (restore_dar_alloc_structs_v3(session, jname) < 0)
3167                 return (-1);
3168 
3169         sels = setupsels(session, params, nlp, dar_index);
3170         if (!sels) {
3171                 free_dar_structs_v3(session, jname);
3172                 return (-1);
3173         }
3174         excl = NULL;
3175         flags = RSFLG_OVR_ALWAYS;
3176         rn.rn_nlp = nlp;
3177         rn.rn_fp = mknewname;
3178 
3179         if (!session->ns_data.dd_abort) {
3180                 cmds = &nlp->nlp_cmds;
3181                 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3182                 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3183                 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3184 
3185                 arg.tr_session = session;
3186                 arg.tr_mod_params = params;
3187                 arg.tr_cmds = cmds;
3188 
3189                 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3190                     (void *)&arg);
3191                 if (err == 0) {
3192                         tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3193                 } else {
3194                         NDMP_LOG(LOG_DEBUG, "launch ndmp_tar_reader: %m");
3195                         return (-1);
3196                 }
3197 
3198                 cmds->tcs_command->tc_ref++;
3199                 cmds->tcs_writer_count++;
3200 
3201                 /* Plug-in module */
3202                 if (ndmp_pl != NULL &&
3203                     ndmp_pl->np_pre_restore != NULL) {
3204                         (void) memset(&nctx, 0, sizeof (ndmp_context_t));
3205                         nctx.nc_cmds = cmds;
3206                         nctx.nc_params = params;
3207                         nctx.nc_ddata = (void *) session;
3208                         ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params,
3209                             dar_index - 1);
3210 
3211                         if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx,
3212                             ep->nm3_opath, ep->nm3_dpath))
3213                             != 0) {
3214                                 NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
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                         char errbuf[256];
3225 
3226                         err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3227                             nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags,
3228                             dar_index, nlp->nlp_backup_path,
3229                             session->hardlink_q);
3230                         /*
3231                          * If the fatal error from tm_getdir looks like an
3232                          * errno code, we send the error description to DMA.
3233                          */
3234                         if (err > 0 && strerror_r(err, errbuf,
3235                             sizeof (errbuf)) == 0) {
3236                                 MOD_LOGV3(params, NDMP_LOG_ERROR,
3237                                     "Fatal error during the restore: %s\n",
3238                                     errbuf);
3239                         }
3240                 }
3241 
3242                 cmds->tcs_writer_count--;
3243                 cmds->tcs_command->tc_ref--;
3244                 NDMP_LOG(LOG_DEBUG, "stop local reader.");
3245                 ndmp_stop_local_reader(session, cmds);
3246 
3247                 ndmp_wait_for_reader(cmds);
3248                 (void) pthread_join(rdtp, NULL);
3249 
3250                 /*
3251                  * If this is the last DAR entry and it is a three-way
3252                  * restore then we should close the connection.
3253                  */
3254                 if ((data_addr_type == NDMP_ADDR_TCP) &&
3255                     (dar_index == (int)session->ns_data.dd_nlist_len)) {
3256                         NDMP_LOG(LOG_DEBUG, "stop remote reader.");
3257                         ndmp_stop_remote_reader(session);
3258                 }
3259 
3260                 /* exit as if there was an internal error */
3261                 if (session->ns_eof)
3262                         err = -1;
3263 restore_out:
3264                 /* Plug-in module */
3265                 if (ndmp_pl != NULL &&
3266                     ndmp_pl->np_post_restore != NULL &&
3267                     ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3268                         NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
3269                         err = -1;
3270                 }
3271         }
3272 
3273         NDMP_FREE(sels);
3274 
3275         free_dar_structs_v3(session, jname);
3276 
3277         return (err);
3278 }
3279 
3280 /*
3281  * ndmpd_dar_locate_windwos_v3
3282  *
3283  * Locating the right window in which the requested file is backed up.
3284  * We should go through windows to find the exact location, for the
3285  * file can be located in for example 10th window after the current window.
3286  *
3287  * Parameters:
3288  *   session (input) - pointer to the session
3289  *   params (input) - pointer to the parameters structure
3290  *   fh_info (input) - index from the beginning of the backup stream
3291  *   len (input) - Length of the mover window
3292  *
3293  * Returns:
3294  *   0: on success
3295  *   -1: on error
3296  */
3297 static int
3298 ndmpd_dar_locate_window_v3(ndmpd_session_t *session,
3299     ndmpd_module_params_t *params, u_longlong_t fh_info, u_longlong_t len)
3300 {
3301         int ret = 0;
3302 
3303 
3304         for (; ; ) {
3305                 ret = (*params->mp_seek_func)(session, fh_info, len);
3306 
3307                 NDMP_LOG(LOG_DEBUG, "ret %d", ret);
3308                 if (ret == 0) /* Seek was done successfully */
3309                         break;
3310                 else if (ret < 0) {
3311                         NDMP_LOG(LOG_DEBUG, "Seek error");

3312                         break;
3313                 }
3314 
3315                 /*
3316                  * DMA moved to a new window.
3317                  * If we are reading the remainig of the file from
3318                  * new window, seek is handled by ndmpd_local_read_v3.
3319                  * Here we should continue the seek inside the new
3320                  * window.
3321                  */
3322                 continue;
3323         }
3324         return (ret);
3325 }
3326 
3327 /*
3328  * ndmpd_rs_dar_tar_v3
3329  *
3330  * Main DAR function. It calls the constructor, then for each entry it
3331  * calls the locate_window_v3 to find the exact position of the file. Then


3352         int n = session->ns_data.dd_nlist_len;
3353         int i, ret = 0;
3354         int result = 0;
3355 
3356         jname = ndmpd_dar_tar_init_v3(session, nlp);
3357 
3358         if (!jname)
3359                 return (-1);
3360 
3361         /*
3362          * We set the length = sizeof (tlm_tar_hdr_t)
3363          * This is important for three-way DAR restore, for we should
3364          * read the header first (If we ask for more data then we have
3365          * to read and discard the remaining data in the socket)
3366          */
3367         len = tlm_tarhdr_size();
3368 
3369         for (i = 0; i < n; ++i) {
3370                 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
3371                 if (!ep) {
3372                         NDMP_LOG(LOG_DEBUG, "ep NULL, i %d", i);
3373                         continue;
3374                 }
3375                 NDMP_LOG(LOG_DEBUG,
3376                     "restoring opath %s, dpath %s, fh_info %lld",
3377                     ep->nm3_opath ? ep->nm3_opath : "NULL",
3378                     ep->nm3_dpath ? ep->nm3_dpath : "NULL",
3379                     ep->nm3_fh_info);
3380 
3381                 /*
3382                  * We should seek till finding the window in which file
3383                  * is located.
3384                  */
3385                 ret = ndmpd_dar_locate_window_v3(session, params,
3386                     ep->nm3_fh_info, len);
3387 
3388                 if (ret < 0) /* If seek fails, restore should be aborted */
3389                         break;
3390                 /*
3391                  * We are inside the target window.
3392                  * for each restore we will use one entry as selection list
3393                  */
3394                 if ((ret = ndmpd_dar_tar_v3(session, params, nlp, jname, i+1))
3395                     != 0)
3396                         result = EIO;
3397                 ndmpd_audit_restore(session->ns_connection,
3398                     ep->nm3_opath ? ep->nm3_opath : "NULL",
3399                     session->ns_data.dd_data_addr.addr_type,
3400                     session->ns_tape.td_adapter_name, result);
3401         }
3402 
3403         NDMP_LOG(LOG_DEBUG, "End of restore list");
3404 
3405         (void) ndmpd_dar_tar_end_v3(session, params, nlp, jname);
3406 
3407         return (ret);
3408 }
3409 
3410 /*
3411  * ndmp_plugin_pre_restore
3412  *
3413  * Wrapper for pre-restore callback with multiple path
3414  */
3415 static int
3416 ndmp_plugin_pre_restore(ndmp_context_t *ctxp, ndmpd_module_params_t *params,
3417     int ncount)
3418 {
3419         mem_ndmp_name_v3_t *ep;
3420         int err;
3421         int i;
3422 
3423         for (i = 0; i < ncount; i++) {


3441  *
3442  * /backup/path/ -> /backup/path
3443  * /backup/path/. -> /backup/path
3444  * /backup/path/../path/ -> /backup/path
3445  * /link-to-backup-path -> /backup/path
3446  *
3447  * Returns:
3448  *      Pointer to the new path (allocated)
3449  *      NULL if the path doesnt exist
3450  */
3451 static char *
3452 get_absolute_path(const char *bkpath)
3453 {
3454         char *pbuf;
3455         char *rv;
3456 
3457         if (!(pbuf = ndmp_malloc(TLM_MAX_PATH_NAME)))
3458                 return (NULL);
3459 
3460         if ((rv = realpath(bkpath, pbuf)) == NULL) {
3461                 NDMP_LOG(LOG_DEBUG, "Invalid path [%s] err=%d",
3462                     bkpath, errno);
3463         }
3464         return (rv);
3465 }
3466 
3467 /*
3468  * Expands the format string and logs the resulting message to the
3469  * remote DMA
3470  */
3471 void
3472 ndmp_log_dma(ndmp_context_t *nctx, ndmp_log_dma_type_t lt, const char *fmt, ...)
3473 {
3474         va_list ap;
3475         char buf[256];
3476         ndmpd_module_params_t *params;
3477 
3478         if (nctx == NULL ||
3479             (params = (ndmpd_module_params_t *)nctx->nc_params) == NULL)
3480                 return;
3481 


3489 
3490 /*
3491  * ndmpd_rs_sar_tar_v3
3492  *
3493  * Main non-DAR restore function. It will try to restore all the entries
3494  * that have been backed up.
3495  *
3496  * Parameters:
3497  *   session (input) - pointer to the session
3498  *   params (input) - pointer to the parameters structure
3499  *   nlp (input) - pointer to the nlp structure
3500  *
3501  * Returns:
3502  *   0: on success
3503  *   -1: on error
3504  */
3505 static int
3506 ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3507     ndmp_lbr_params_t *nlp)
3508 {
3509         char jname[TLM_MAX_BACKUP_JOB_NAME];
3510         char *excl;
3511         char **sels;
3512         int flags;
3513         int err;
3514         tlm_commands_t *cmds;
3515         struct rs_name_maker rn;
3516         ndmp_tar_reader_arg_t arg;
3517         pthread_t rdtp;
3518         int result;
3519         ndmp_context_t nctx;
3520 
3521         result = err = 0;
3522         (void) ndmp_new_job_name(jname);
3523         if (restore_alloc_structs_v3(session, jname) < 0)
3524                 return (-1);
3525 



3526         sels = setupsels(session, params, nlp, 0);
3527         if (!sels) {
3528                 free_structs_v3(session, jname);
3529                 return (-1);
3530         }
3531         excl = NULL;
3532         flags = RSFLG_OVR_ALWAYS;
3533         rn.rn_nlp = nlp;
3534         rn.rn_fp = mknewname;
3535 
3536         nlp->nlp_jstat->js_start_ltime = time(NULL);
3537         nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3538 
3539         if (!session->ns_data.dd_abort && !session->ns_data.dd_abort) {
3540                 cmds = &nlp->nlp_cmds;
3541                 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3542                 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3543                 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3544 
3545                 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.",
3546                     (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3547 
3548                 arg.tr_session = session;
3549                 arg.tr_mod_params = params;
3550                 arg.tr_cmds = cmds;
3551                 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3552                     (void *)&arg);
3553                 if (err == 0) {
3554                         tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3555                 } else {
3556                         NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
3557                         free_structs_v3(session, jname);
3558                         return (-1);
3559                 }
3560 
3561                 if (!ndmp_check_utf8magic(cmds->tcs_command)) {
3562                         NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!");
3563                 } else {
3564                         NDMP_LOG(LOG_DEBUG, "UTF8Magic found");
3565                 }
3566 
3567                 /* Plug-in module */
3568                 if (ndmp_pl != NULL &&
3569                     ndmp_pl->np_pre_restore != NULL) {
3570                         (void) memset(&nctx, 0, sizeof (ndmp_context_t));
3571                         nctx.nc_cmds = cmds;
3572                         nctx.nc_params = params;
3573                         nctx.nc_ddata = (void *) session;
3574                         if ((err = ndmp_plugin_pre_restore(&nctx, params,
3575                             nlp->nlp_nfiles))
3576                             != 0) {
3577                                 NDMP_LOG(LOG_ERR, "Pre-restore plug-in: %m");
3578                                 ndmp_stop_local_reader(session, cmds);
3579                                 ndmp_wait_for_reader(cmds);
3580                                 (void) pthread_join(rdtp, NULL);
3581                                 ndmp_stop_remote_reader(session);
3582                                 goto restore_out;
3583                         }
3584                 }
3585 
3586                 cmds->tcs_command->tc_ref++;
3587                 cmds->tcs_writer_count++;
3588 
3589                 if (tm_tar_ops.tm_getdir != NULL) {
3590                         char errbuf[256];
3591 
3592                         err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3593                             nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 0,
3594                             nlp->nlp_backup_path, session->hardlink_q);
3595                         /*
3596                          * If the fatal error from tm_getdir looks like an
3597                          * errno code, we send the error description to DMA.
3598                          */
3599                         if (err > 0 && strerror_r(err, errbuf,
3600                             sizeof (errbuf)) == 0) {
3601                                 MOD_LOGV3(params, NDMP_LOG_ERROR,
3602                                     "Fatal error during the restore: %s\n",
3603                                     errbuf);
3604                         }
3605                 }
3606 
3607                 cmds->tcs_writer_count--;
3608                 cmds->tcs_command->tc_ref--;
3609                 nlp->nlp_jstat->js_stop_time = time(NULL);
3610 
3611                 /* Send the list of un-recovered files/dirs to the client.  */
3612                 (void) send_unrecovered_list_v3(params, nlp);
3613 
3614                 ndmp_stop_local_reader(session, cmds);
3615                 ndmp_wait_for_reader(cmds);
3616                 (void) pthread_join(rdtp, NULL);
3617 
3618                 ndmp_stop_remote_reader(session);
3619 
3620                 /* exit as if there was an internal error */
3621                 if (session->ns_eof)
3622                         err = -1;
3623                 if (err == -1)
3624                         result = EIO;
3625         }
3626 
3627         (void) send_unrecovered_list_v3(params, nlp); /* nothing restored. */
3628         if (session->ns_data.dd_abort) {
3629                 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3630                     (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3631                 result = EINTR;
3632                 ndmpd_audit_restore(session->ns_connection,
3633                     nlp->nlp_restore_path,
3634                     session->ns_data.dd_data_addr.addr_type,
3635                     session->ns_tape.td_adapter_name, result);
3636                 err = -1;
3637         } else {
3638                 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3639                     (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL",
3640                     err);
3641                 ndmpd_audit_restore(session->ns_connection,
3642                     nlp->nlp_restore_path,
3643                     session->ns_data.dd_data_addr.addr_type,
3644                     session->ns_tape.td_adapter_name, result);
3645 
3646 restore_out:
3647                 /* Plug-in module */
3648                 if (ndmp_pl != NULL &&
3649                     ndmp_pl->np_post_restore != NULL &&
3650                     ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3651                         NDMP_LOG(LOG_DEBUG, "Post-restore plug-in: %m");
3652                         err = -1;
3653                 }
3654         }
3655 
3656         NDMP_FREE(sels);
3657         free_structs_v3(session, jname);
3658 
3659         return (err);
3660 }
3661 
3662 
3663 /*
3664  * ndmp_backup_get_params_v3
3665  *
3666  * Get the backup parameters from the NDMP env variables
3667  * and log them in the system log and as normal messages
3668  * to the DMA.
3669  *
3670  * Parameters:
3671  *   session (input) - pointer to the session
3672  *   params (input) - pointer to the parameters structure
3673  *
3674  * Returns:
3675  *   NDMP_NO_ERR: on success
3676  *   != NDMP_NO_ERR: otherwise
3677  */
3678 ndmp_error
3679 ndmp_backup_get_params_v3(ndmpd_session_t *session,
3680     ndmpd_module_params_t *params)
3681 {
3682         ndmp_lbr_params_t *nlp;
3683 
3684         if (!session || !params)
3685                 return (NDMP_ILLEGAL_ARGS_ERR);
3686 
3687         nlp = ndmp_get_nlp(session);
3688         if (!nlp) {
3689                 MOD_LOGV3(params, NDMP_LOG_ERROR,
3690                     "Internal error: NULL nlp.\n");
3691                 return (NDMP_ILLEGAL_ARGS_ERR);
3692         } else {
3693                 if (!(nlp->nlp_backup_path = get_backup_path_v3(params)) ||
3694                     !is_valid_backup_dir_v3(params, nlp->nlp_backup_path))
3695                 return (NDMP_ILLEGAL_ARGS_ERR);
3696         }
3697 
3698         nlp->nlp_backup_path = get_absolute_path(nlp->nlp_backup_path);
3699         if (!nlp->nlp_backup_path)
3700                 return (NDMP_ILLEGAL_ARGS_ERR);
3701 
3702         if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
3703             fs_is_rdonly(nlp->nlp_backup_path) ||
3704             !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
3705                 NLP_SET(nlp, NLPF_CHKPNTED_PATH);
3706         else
3707                 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
3708 































3709         /* Should the st_ctime be ignored when backing up? */
3710         if (ndmp_ignore_ctime) {
3711                 NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
3712                 NLP_SET(nlp, NLPF_IGNCTIME);
3713         } else {
3714                 NLP_UNSET(nlp, NLPF_IGNCTIME);
3715         }
3716 
3717         if (ndmp_include_lmtime == TRUE) {
3718                 NDMP_LOG(LOG_DEBUG, "including st_lmtime");
3719                 NLP_SET(nlp, NLPF_INCLMTIME);
3720         } else {
3721                 NLP_UNSET(nlp, NLPF_INCLMTIME);
3722         }
3723 
3724         NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
3725 
3726         get_hist_env_v3(params, nlp);
3727         get_exc_env_v3(params, nlp);
3728         get_inc_env_v3(params, nlp);
3729         get_direct_env_v3(params, nlp);
3730         return (get_backup_level_v3(params, nlp));
3731 }
3732 
3733 
3734 /*
3735  * ndmpd_tar_backup_starter_v3
3736  *
3737  * Create the checkpoint for the backup and do the backup,
3738  * then remove the backup checkpoint if we created it.
3739  * Save the backup time information based on the backup
3740  * type and stop the data server.
3741  *
3742  * Parameters:
3743  *   params (input) - pointer to the parameters structure
3744  *
3745  * Returns:
3746  *   0: on success
3747  *   != 0: otherwise
3748  */
3749 int
3750 ndmpd_tar_backup_starter_v3(void *arg)
3751 {
3752         ndmpd_module_params_t *params = arg;
3753         int err;
3754         ndmpd_session_t *session;
3755         ndmp_lbr_params_t *nlp;
3756         char jname[TLM_MAX_BACKUP_JOB_NAME];
3757         ndmp_bkup_size_arg_t sarg;
3758         pthread_t tid;
3759 
3760         session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3761         *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3762         ndmp_session_ref(session);
3763         (void) ndmp_new_job_name(jname);
3764 


3765         err = 0;
3766         if (!NLP_ISCHKPNTED(nlp) &&
3767             ndmp_create_snapshot(nlp->nlp_backup_path, jname) < 0) {
3768                 MOD_LOGV3(params, NDMP_LOG_ERROR,
3769                     "Creating checkpoint on \"%s\".\n",
3770                     nlp->nlp_backup_path);
3771                 err = -1;
3772         }
3773 
3774         NDMP_LOG(LOG_DEBUG, "err %d, chkpnted %c",
3775             err, NDMP_YORN(NLP_ISCHKPNTED(nlp)));
3776 
3777         if (err == 0) {
3778                 sarg.bs_session = session;
3779                 sarg.bs_jname = jname;
3780                 sarg.bs_path = nlp->nlp_backup_path;
3781 
3782                 /* Get an estimate of the data size */
3783                 if (pthread_create(&tid, NULL, (funct_t)get_backup_size,
3784                     (void *)&sarg) == 0)
3785                         (void) pthread_detach(tid);
3786 
3787                 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate, jname);
3788                 if (err != 0) {
3789                         NDMP_LOG(LOG_DEBUG, "err %d", err);

3790                 } else {
3791                         log_bk_params_v3(session, params, nlp);
3792                         err = tar_backup_v3(session, params, nlp, jname);
3793                 }
3794         }
3795 
3796         if (!NLP_ISCHKPNTED(nlp))
3797                 (void) ndmp_remove_snapshot(nlp->nlp_backup_path, jname);
3798 
3799         NDMP_LOG(LOG_DEBUG, "err %d, update %c",
3800             err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
3801 
3802         if (err == 0)
3803                 save_backup_date_v3(params, nlp);
3804 
3805         MOD_DONE(params, err);
3806 
3807         /* nlp_params is allocated in start_backup_v3() */
3808         NDMP_FREE(nlp->nlp_params);
3809         NDMP_FREE(nlp->nlp_backup_path);
3810 
3811         NS_DEC(nbk);
3812         ndmp_session_unref(session);


3813         return (err);
3814 
3815 }
3816 
3817 
3818 /*
3819  * ndmpd_tar_backup_abort_v3
3820  *
3821  * Abort the backup operation and stop the reader thread.
3822  *
3823  * Parameters:
3824  *   module_cookie (input) - pointer to the nlp structure
3825  *
3826  * Returns:
3827  *   0: always
3828  */
3829 int
3830 ndmpd_tar_backup_abort_v3(void *module_cookie)
3831 {
3832         ndmp_lbr_params_t *nlp;
3833 
3834         nlp = (ndmp_lbr_params_t *)module_cookie;


3851  *
3852  * Get the parameters specified for recovery such as restore path, type
3853  * of restore (DAR, non-DAR) etc
3854  *
3855  * Parameters:
3856  *   session (input) - pointer to the session
3857  *   params (input) - pointer to the parameters structure
3858  *
3859  * Returns:
3860  *   NDMP_NO_ERR: on success
3861  *   != NDMP_NO_ERR: otherwise
3862  */
3863 ndmp_error
3864 ndmp_restore_get_params_v3(ndmpd_session_t *session,
3865     ndmpd_module_params_t *params)
3866 {
3867         ndmp_error rv;
3868         ndmp_lbr_params_t *nlp;
3869 
3870         if (!(nlp = ndmp_get_nlp(session))) {
3871                 NDMP_LOG(LOG_DEBUG, "nlp is NULL");
3872                 rv = NDMP_ILLEGAL_ARGS_ERR;
3873         } else if (!(nlp->nlp_backup_path = get_backup_path_v3(params)))
3874                 rv = NDMP_ILLEGAL_ARGS_ERR;
3875         else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) {
3876                 NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
3877                 rv = NDMP_ILLEGAL_ARGS_ERR;
3878         } else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) {
3879                 rv = NDMP_ILLEGAL_ARGS_ERR;
3880         } else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) {
3881                 NDMP_LOG(LOG_DEBUG, "fix_nlist_v3: %d", rv);
3882         } else {
3883                 rv = NDMP_NO_ERR;
3884                 get_direct_env_v3(params, nlp);
3885                 if (NLP_ISSET(nlp, NLPF_DIRECT)) {
3886                         if (NLP_ISSET(nlp, NLPF_RECURSIVE)) {
3887                                 /* Currently we dont support DAR on directory */
3888                                 NDMP_LOG(LOG_DEBUG,
3889                                     "Can't have RECURSIVE and DIRECT together");
3890                                 rv = NDMP_ILLEGAL_ARGS_ERR;
3891                                 return (rv);
3892                         }
3893 
3894                         /*
3895                          * DAR can be done if all the fh_info's are valid.
3896                          */
3897                         if (allvalidfh(session, params)) {
3898                                 ndmp_sort_nlist_v3(session);
3899                         } else {
3900                                 MOD_LOGV3(params, NDMP_LOG_WARNING,
3901                                     "Cannot do direct access recovery. "
3902                                     "Some 'fh_info'es are not valid.\n");
3903                                 NLP_UNSET(nlp, NLPF_DIRECT);
3904                         }
3905                 }
3906 
3907                 log_rs_params_v3(session, params, nlp);
3908         }




  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 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
  41 
  42 #include <sys/stat.h>
  43 #include <sys/types.h>
  44 #include <sys/time.h>
  45 #include <syslog.h>
  46 #include <ctype.h>
  47 #include <sys/socket.h>
  48 #include <sys/acl.h>
  49 #include <netinet/in.h>
  50 #include <arpa/inet.h>
  51 #include <errno.h>
  52 #include <stdio.h>
  53 #include <string.h>
  54 #include <time.h>
  55 #include <cstack.h>
  56 #include "ndmp.h"
  57 #include "ndmpd.h"
  58 #include <bitmap.h>
  59 #include <traverse.h>
  60 
  61 
  62 /*
  63  * Maximum length of the string-representation of u_longlong_t type.
  64  */
  65 #define QUAD_DECIMAL_LEN        20


  98 } bk_param_v3_t;
  99 
 100 
 101 /*
 102  * Multiple destination restore mode
 103  */
 104 #define MULTIPLE_DEST_DIRS 128
 105 
 106 int multiple_dest_restore = 0;
 107 
 108 /*
 109  * Plug-in module ops
 110  */
 111 ndmp_plugin_t *ndmp_pl;
 112 
 113 /*
 114  * NDMP exclusion list
 115  */
 116 char **ndmp_excl_list = NULL;
 117 
 118 extern boolean_t fs_is_checkpointed(ndmp_lbr_params_t *);
 119 
 120 /*
 121  * split_env
 122  *
 123  * Splits the string into list of sections separated by the
 124  * sep character.
 125  *
 126  * Parameters:
 127  *   envp (input) - the environment variable that should be broken
 128  *   sep (input) - the separator character
 129  *
 130  * Returns:
 131  *   Array of character pointers: On success.  The array is allocated
 132  *      as well as all its entries.  They all should be freed by the
 133  *      caller.
 134  *   NULL: on error
 135  */
 136 static char **
 137 split_env(char *envp, char sep)
 138 {
 139         char *bp, *cp, *ep;


 222         return (cpp);
 223 }
 224 
 225 
 226 /*
 227  * prl
 228  *
 229  * Print the array of character pointers passed to it.  This is
 230  * used for debugging purpose.
 231  *
 232  * Parameters:
 233  *   lpp (input) - pointer to the array of strings
 234  *
 235  * Returns:
 236  *   void
 237  */
 238 static void
 239 prl(char **lpp)
 240 {
 241         if (!lpp) {
 242                 syslog(LOG_DEBUG, "empty");
 243                 return;
 244         }
 245 
 246         while (*lpp)
 247                 syslog(LOG_DEBUG, "\"%s\"", *lpp++);
 248 }
 249 
 250 
 251 /*
 252  * inlist
 253  *
 254  * Looks through all the strings of the array to see if the ent
 255  * matches any of the strings.  The strings are patterns.
 256  *
 257  * Parameters:
 258  *   lpp (input) - pointer to the array of strings
 259  *   ent (input) - the entry to be matched
 260  *
 261  * Returns:
 262  *   TRUE: if there is a match
 263  *   FALSE: invalid argument or no match
 264  */
 265 static boolean_t
 266 inlist(char **lpp, char *ent)
 267 {
 268         if (!lpp || !ent) {
 269                 syslog(LOG_DEBUG, "empty list");
 270                 return (FALSE);
 271         }
 272 
 273         while (*lpp) {
 274                 /*
 275                  * Fixing the sync_sort NDMPV3 problem, it sends the inclusion
 276                  * like "./" which we should skip the "./"
 277                  */
 278                 char *pattern = *lpp;
 279                 if (strncmp(pattern, "./", 2) == 0)
 280                         pattern += 2;
 281 
 282                 syslog(LOG_DEBUG, "pattern %s, ent %s", pattern, ent);
 283 
 284                 if (match(pattern, ent)) {
 285                         syslog(LOG_DEBUG, "match(%s,%s)", pattern, ent);
 286                         return (TRUE);
 287                 }
 288                 lpp++;
 289         }
 290 
 291         syslog(LOG_DEBUG, "no match");
 292         return (FALSE);
 293 }
 294 
 295 
 296 /*
 297  * inexl
 298  *
 299  * Checks if the entry is in the list.  This is used for exclusion
 300  * list.  If the exclusion list is empty, FALSE should be returned
 301  * showing that nothing should be excluded by default.
 302  *
 303  * Parameters:
 304  *   lpp (input) - pointer to the array of strings
 305  *   ent (input) - the entry to be matched
 306  *
 307  * Returns:
 308  *   TRUE: if there is a match
 309  *   FALSE: invalid argument or no match
 310  *
 311  */


 397                 lpp += start; /* Next selection entry will be in lpp[start] */
 398         } else {
 399                 start = 0;
 400                 end = n;
 401         }
 402 
 403         for (i = start; i < end; i++) {
 404                 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
 405                 if (!ep)
 406                         continue;
 407 
 408                 /*
 409                  * Check for clients that send original path as "."(like
 410                  * CA products). In this situation opath is something like
 411                  * "/v1/." and we should change it to "/v1/"
 412                  */
 413                 len = strlen(ep->nm3_opath);
 414                 if (len > 1 && ep->nm3_opath[len-2] == '/' &&
 415                     ep->nm3_opath[len-1] == '.') {
 416                         ep->nm3_opath[len-1] = '\0';
 417                         syslog(LOG_DEBUG,
 418                             "nm3_opath changed from %s. to %s",
 419                             ep->nm3_opath, ep->nm3_opath);
 420                 }
 421                 *lpp++ = ep->nm3_opath;
 422         }
 423 
 424         /* list termination indicator is a null pointer */
 425         *lpp = NULL;
 426 
 427         return (save);
 428 }
 429 
 430 
 431 /*
 432  * mkrsp
 433  *
 434  * Make Restore Path.
 435  * It gets a path, a selection (with which the path has matched) a new
 436  * name and makes a new name for the path.
 437  * All the components of the path and the selection are skipped as long


 472                 if (!COMPBNDRY(pp) || !COMPBNDRY(sp))
 473                         /* An exception to the boundary rule */
 474                         /* (!(!*sp && (*(pp - 1)) == '/')) */
 475                         if (*sp || (*(pp - 1)) != '/')
 476                                 return (NULL);
 477 
 478                 /* if pp shorter than sp, it should not be restored */
 479                 if (!*pp && *sp) {
 480                         sp += strspn(sp, "/");
 481                         if (strlen(sp) > 0)
 482                                 return (NULL);
 483                 }
 484         }
 485 
 486         if (np)
 487                 np += strspn(np, "/");
 488         else
 489                 np = "";
 490 
 491         if (!tlm_cat_path(bp, np, pp)) {
 492                 syslog(LOG_ERR, "Restore path too long %s/%s.", np, pp);
 493                 return (NULL);
 494         }
 495 
 496         return (bp);
 497 }
 498 
 499 
 500 /*
 501  * mknewname
 502  *
 503  * This is used as callback for creating the restore path. This function
 504  * can handle both single destination and multiple restore paths.
 505  *
 506  * Make up the restore destination path for a particular file/directory, path,
 507  * based on nm3_opath and nm3_dpath.  path should have matched nm3_opath
 508  * in some way.
 509  */
 510 char *
 511 mknewname(struct rs_name_maker *rnp, char *buf, int idx, char *path)
 512 {
 513         char *rv;
 514         ndmp_lbr_params_t *nlp;
 515         mem_ndmp_name_v3_t *ep;
 516 
 517         rv = NULL;
 518         if (!buf) {
 519                 syslog(LOG_DEBUG, "buf is NULL");
 520         } else if (!path) {
 521                 syslog(LOG_DEBUG, "path is NULL");
 522         } else if ((nlp = rnp->rn_nlp) == 0) {
 523                 syslog(LOG_DEBUG, "rnp->rn_nlp is NULL");
 524         } else if (!nlp->nlp_params) {
 525                 syslog(LOG_DEBUG, "nlp->nlp_params is NULL");
 526         } else
 527                 if (!ndmp_full_restore_path) {
 528                         if (idx < 0 || idx >= (int)nlp->nlp_nfiles) {
 529                                 syslog(LOG_DEBUG,
 530                                     "Invalid idx %d range (0, %d)",
 531                                     idx, nlp->nlp_nfiles);
 532                         } else if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(
 533                             nlp->nlp_params, idx))) {
 534                                 syslog(LOG_DEBUG,
 535                                     "nlist entry %d is NULL", idx);
 536                         } else {
 537                                 rv = mkrsp(buf, path, ep->nm3_opath,
 538                                     ep->nm3_dpath);










 539                         }

 540                 } else {
 541                         if (!tlm_cat_path(buf, nlp->nlp_restore_path, path)) {
 542                                 syslog(LOG_ERR, "Path too long %s/%s.",
 543                                     nlp->nlp_restore_path, path);
 544                                 rv = NULL;
 545                         } else {
 546                                 rv = buf;


 547                         }
 548                 }
 549 
 550         return (rv);
 551 }
 552 
 553 
 554 /*
 555  * chopslash
 556  *
 557  * Remove the slash from the end of the given path
 558  */
 559 static void
 560 chopslash(char *cp)
 561 {
 562         int ln;
 563 
 564         if (!cp || !*cp)
 565                 return;
 566 


 594         }
 595 
 596         return (bp);
 597 }
 598 
 599 
 600 /*
 601  * voliswr
 602  *
 603  * Is the volume writable?
 604  */
 605 static int
 606 voliswr(char *path)
 607 {
 608         int rv;
 609 
 610         if (!path)
 611                 return (0);
 612 
 613         rv = !fs_is_rdonly(path) && !fs_is_chkpntvol(path);
 614         syslog(LOG_DEBUG, "%d path \"%s\"", rv, path);
 615         return (rv);
 616 
 617 }
 618 
 619 
 620 /*
 621  * is_valid_backup_dir_v3
 622  *
 623  * Checks the validity of the backup path.  Backup path should
 624  * have the following characteristics to be valid:
 625  *      1) It should be an absolute path.
 626  *      2) It should be a directory.
 627  *      3) It should not be checkpoint root directory
 628  *      4) If the file system is read-only, the backup path
 629  *          should be a checkpointed path.  Checkpoint cannot
 630  *          be created on a read-only file system.
 631  *
 632  * Parameters:
 633  *   params (input) - pointer to the parameters structure.
 634  *   bkpath (input) - the backup path


 763 /*
 764  * log_bk_params_v3
 765  *
 766  * Dispatcher function which calls the appropriate function
 767  * for logging the backup date and level in the system log
 768  * and also send them as normal log message to the client.
 769  *
 770  * Parameters:
 771  *   session (input) - pointer to the session
 772  *   params (input) - pointer to the parameters structure
 773  *   nlp (input) - pointer to the nlp structure
 774  *
 775  * Returns:
 776  *   void
 777  */
 778 static void
 779 log_bk_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
 780     ndmp_lbr_params_t *nlp)
 781 {
 782         MOD_LOGV3(params, NDMP_LOG_NORMAL, "Backing up \"%s\".\n",
 783             NLP_ISCHKPNTED(nlp) ? nlp->nlp_mountpoint : nlp->nlp_backup_path);
 784 
 785         if (session->ns_mover.md_data_addr.addr_type == NDMP_ADDR_LOCAL)
 786                 MOD_LOGV3(params, NDMP_LOG_NORMAL,
 787                     "Tape record size: %d.\n",
 788                     session->ns_mover.md_record_size);
 789 
 790         MOD_LOGV3(params, NDMP_LOG_NORMAL, "File history: %c.\n",
 791             NDMP_YORN(NLP_ISSET(nlp, NLPF_FH)));
 792 
 793         if (NLP_ISSET(nlp, NLPF_TOKENBK))
 794                 log_date_token_v3(params, nlp);
 795         else if (NLP_ISSET(nlp, NLPF_LBRBK))
 796                 log_lbr_bk_v3(params, nlp);
 797         else if (NLP_ISSET(nlp, NLPF_LEVELBK))
 798                 log_level_v3(params, nlp);
 799         else {
 800                 MOD_LOGV3(params, NDMP_LOG_ERROR,
 801                     "Internal error: backup level not defined for \"%s\".\n",
 802                     nlp->nlp_backup_path);
 803         }


 809  *
 810  * Is the UPDATE environment variable specified?  If it is
 811  * the corresponding flag is set in the flags field of the
 812  * nlp structure, otherwise the flag is cleared.
 813  *
 814  * Parameters:
 815  *   params (input) - pointer to the parameters structure
 816  *   nlp (input) - pointer to the nlp structure
 817  *
 818  * Returns:
 819  *   void
 820  */
 821 static void
 822 get_update_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 823 {
 824         char *envp;
 825 
 826         envp = MOD_GETENV(params, "UPDATE");
 827         if (!envp) {
 828                 NLP_SET(nlp, NLPF_UPDATE);
 829                 syslog(LOG_DEBUG,
 830                     "env(UPDATE) not defined, default to TRUE");
 831         } else {
 832                 syslog(LOG_DEBUG, "env(UPDATE): \"%s\"", envp);
 833                 if (IS_YORT(*envp))
 834                         NLP_SET(nlp, NLPF_UPDATE);
 835                 else
 836                         NLP_UNSET(nlp, NLPF_UPDATE);
 837         }
 838 }
 839 
 840 
 841 /*
 842  * get_hist_env_v3
 843  *
 844  * Is backup history requested?  If it is, the corresponding
 845  * flag is set in the flags field of the nlp structure, otherwise
 846  * the flag is cleared.
 847  *
 848  * Parameters:
 849  *   params (input) - pointer to the parameters structure
 850  *   nlp (input) - pointer to the nlp structure
 851  *
 852  * Returns:
 853  *   void
 854  */
 855 static void
 856 get_hist_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 857 {
 858         char *envp;
 859 
 860         envp = MOD_GETENV(params, "HIST");
 861         if (!envp) {
 862                 syslog(LOG_DEBUG, "env(HIST) not defined");
 863                 NLP_UNSET(nlp, NLPF_FH);
 864         } else {
 865                 syslog(LOG_DEBUG, "env(HIST): \"%s\"", envp);
 866                 if (IS_YORT(*envp) || IS_F(*envp))
 867                         NLP_SET(nlp, NLPF_FH);
 868                 else
 869                         NLP_UNSET(nlp, NLPF_FH);
 870 
 871                 /* Force file format if specified */
 872                 if (IS_F(*envp)) {
 873                         params->mp_file_history_path_func =
 874                             ndmpd_api_file_history_file_v3;
 875                         params->mp_file_history_dir_func = 0;
 876                         params->mp_file_history_node_func = 0;
 877                 }
 878         }
 879 }
 880 
 881 
 882 /*
 883  * get_exc_env_v3
 884  *
 885  * Gets the EXCLUDE environment variable and breaks it
 886  * into strings.  The separator of the EXCLUDE environment
 887  * variable is the ',' character.
 888  *
 889  * Parameters:
 890  *   params (input) - pointer to the parameters structure
 891  *   nlp (input) - pointer to the nlp structure
 892  *
 893  * Returns:
 894  *   void
 895  */
 896 static void
 897 get_exc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 898 {
 899         char *envp;
 900 
 901         envp = MOD_GETENV(params, "EXCLUDE");
 902         if (!envp) {
 903                 syslog(LOG_DEBUG, "env(EXCLUDE) not defined");
 904                 nlp->nlp_exl = NULL;
 905         } else {
 906                 syslog(LOG_DEBUG, "env(EXCLUDE): \"%s\"", envp);
 907                 nlp->nlp_exl = split_env(envp, ',');
 908                 prl(nlp->nlp_exl);
 909         }
 910 }
 911 
 912 
 913 /*
 914  * get_inc_env_v3
 915  *
 916  * Gets the FILES environment variable that shows which files
 917  * should be backed up, and breaks it into strings.  The
 918  * separator of the FILES environment variable is the space
 919  * character.
 920  *
 921  * Parameters:
 922  *   params (input) - pointer to the parameters structure
 923  *   nlp (input) - pointer to the nlp structure
 924  *
 925  * Returns:
 926  *   void
 927  */
 928 static void
 929 get_inc_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 930 {
 931         char *envp;
 932 
 933         envp = MOD_GETENV(params, "FILES");
 934         if (!envp) {
 935                 syslog(LOG_DEBUG, "env(FILES) not defined");
 936                 nlp->nlp_inc = NULL;
 937         } else {
 938                 syslog(LOG_DEBUG, "env(FILES): \"%s\"", envp);
 939                 nlp->nlp_inc = split_env(envp, ' ');
 940                 prl(nlp->nlp_inc);
 941         }
 942 }
 943 
 944 
 945 /*
 946  * get_direct_env_v3
 947  *
 948  * Gets the DIRECT environment variable that shows if the fh_info should
 949  * be sent to the client or not.
 950  *
 951  * Parameters:
 952  *   params (input) - pointer to the parameters structure
 953  *   nlp (input) - pointer to the nlp structure
 954  *
 955  * Returns:
 956  *   void
 957  */
 958 static void
 959 get_direct_env_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 960 {
 961         char *envp;
 962 
 963         /*
 964          * We should send the fh_info to the DMA, unless it is specified
 965          * in the request that we should not send fh_info.
 966          * At the moment we do not support DAR on directories, so if the user
 967          * needs to restore a directory they should disable the DAR.
 968          */
 969         if (params->mp_operation == NDMP_DATA_OP_RECOVER && !ndmp_dar_support) {
 970                 syslog(LOG_INFO, "Direct Access Restore Disabled");
 971                 NLP_UNSET(nlp, NLPF_DIRECT);
 972                 MOD_LOGV3(params, NDMP_LOG_NORMAL,
 973                     "DAR is disabled. Running Restore without DAR");
 974                 return;
 975         }
 976 
 977         /*
 978          * Regardless of whether DIRECT is defined at backup time we send
 979          * back the fh_info, for some clients do not use get_backup_attrs.
 980          * If operation is restore we have to unset the DIRECT, for
 981          * some clients do not set the MOVER window.
 982          */
 983         if (params->mp_operation == NDMP_DATA_OP_BACKUP) {
 984                 syslog(LOG_DEBUG, "backup default env(DIRECT): YES");
 985                 NLP_SET(nlp, NLPF_DIRECT);
 986         } else {
 987 
 988                 envp = MOD_GETENV(params, "DIRECT");
 989                 if (!envp) {
 990                         syslog(LOG_DEBUG, "env(DIRECT) not defined");
 991                         NLP_UNSET(nlp, NLPF_DIRECT);
 992                 } else {
 993                         syslog(LOG_DEBUG, "env(DIRECT): \"%s\"", envp);
 994                         if (IS_YORT(*envp)) {
 995                                 NLP_SET(nlp, NLPF_DIRECT);
 996                                 syslog(LOG_DEBUG,
 997                                     "Direct Access Restore Enabled");
 998                         } else {
 999                                 NLP_UNSET(nlp, NLPF_DIRECT);
1000                                 syslog(LOG_DEBUG,
1001                                     "Direct Access Restore Disabled");
1002                         }
1003                 }
1004         }
1005 
1006         if (NLP_ISSET(nlp, NLPF_DIRECT)) {
1007                 if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1008                         MOD_LOGV3(params, NDMP_LOG_NORMAL,
1009                             "Direct Access Restore information is supported");
1010                 else
1011                         MOD_LOGV3(params, NDMP_LOG_NORMAL,
1012                             "Running Restore with Direct Access Restore");
1013         } else {
1014                 if (params->mp_operation == NDMP_DATA_OP_BACKUP)
1015                         MOD_LOGV3(params, NDMP_LOG_NORMAL,
1016                             "Direct Access Restore is not supported");
1017                 else
1018                         MOD_LOGV3(params, NDMP_LOG_NORMAL,
1019                             "Running Restore without Direct Access Restore");
1020         }


1060                 return (NDMP_ILLEGAL_ARGS_ERR);
1061 
1062         if (MOD_GETENV(params, "LEVEL")) {
1063                 MOD_LOGV3(params, NDMP_LOG_WARNING,
1064                     "Both BASE_DATE and LEVEL environment variables "
1065                     "defined.\n");
1066                 MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1067                     "BASE_DATE is being used for this backup.\n");
1068         }
1069 
1070         tok = strtoll(basedate, &endp, 10);
1071         if (endp == basedate) {
1072                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1073                     "Invalid BASE_DATE environment variable: \"%s\".\n",
1074                     basedate);
1075                 return (NDMP_ILLEGAL_ARGS_ERR);
1076         }
1077 
1078         tstamp = tok & 0xffffffff;
1079         seq = (tok >> 32) & 0xffffffff;


1080 
1081         if ((int)seq > ndmp_get_max_tok_seq()) {
1082                 rv = NDMP_ILLEGAL_ARGS_ERR;
1083                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1084                     "The sequence counter of the token exceeds the "
1085                     "maximum permitted value.\n");
1086                 MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1087                     "Token sequence: %u, maxiumum value: %u.\n",
1088                     seq, ndmp_get_max_tok_seq());
1089         } else if (seq >= NDMP_TOKSEQ_HLIMIT) {
1090                 rv = NDMP_ILLEGAL_ARGS_ERR;
1091                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1092                     "The sequence counter the of token exceeds the "
1093                     "hard-limit.\n");
1094                 MOD_LOGCONTV3(params, NDMP_LOG_ERROR,
1095                     "Token sequence: %u, hard-limit: %u.\n",
1096                     seq, NDMP_TOKSEQ_HLIMIT);
1097         } else {
1098                 rv = NDMP_NO_ERR;
1099                 /*


1199          * If the BASE_DATE env variable is specified use it, otherwise
1200          * look to see if LEVEL is specified.  If LEVEL is not
1201          * specified either, backup level '0' must be made. Level backup
1202          * does not clear the archive bit.
1203          *
1204          * If LEVEL environment varaible is specified, values for
1205          * 'F', 'D', 'I' and 'A' (for 'Full', 'Differential',
1206          * 'Incremental', and 'Archive' is checked first.  Then
1207          * level '0' to '9' will be checked.
1208          *
1209          * LEVEL environment variable can hold only one character.
1210          * If its length is longer than 1, an error is returned.
1211          */
1212         envp = MOD_GETENV(params, "BASE_DATE");
1213         if (envp)
1214                 return (get_date_token_v3(params, nlp, envp));
1215 
1216 
1217         envp = MOD_GETENV(params, "LEVEL");
1218         if (!envp) {
1219                 syslog(LOG_DEBUG, "env(LEVEL) not defined, default to 0");
1220                 NLP_SET(nlp, NLPF_LEVELBK);
1221                 NLP_UNSET(nlp, NLPF_LBRBK);
1222                 NLP_UNSET(nlp, NLPF_TOKENBK);
1223                 nlp->nlp_llevel = 0;
1224                 nlp->nlp_ldate = 0;
1225                 nlp->nlp_clevel = 0;
1226                 /*
1227                  * The value of nlp_cdate will be set to the checkpoint
1228                  * creation time after it is created.
1229                  */
1230                 return (NDMP_NO_ERR);
1231         }
1232 
1233         if (*(envp+1) != '\0') {
1234                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1235                     "Invalid backup level \"%s\".\n", envp);
1236                 return (NDMP_ILLEGAL_ARGS_ERR);
1237         }
1238 
1239         if (IS_LBR_BKTYPE(*envp))


1281  * Parameters:
1282  *   params (input) - pointer to the parameters structure
1283  *   nlp (input) - pointer to the nlp structure
1284  *
1285  * Returns:
1286  *   void
1287  */
1288 static void
1289 save_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1290 {
1291         char val[QUAD_DECIMAL_LEN];
1292         u_longlong_t tok;
1293 
1294         if (!params || !nlp)
1295                 return;
1296 
1297         nlp->nlp_tokseq++;
1298         tok = ((u_longlong_t)nlp->nlp_tokseq << 32) | nlp->nlp_cdate;
1299         (void) snprintf(val, sizeof (val), "%llu", tok);
1300 


1301         if (MOD_SETENV(params, "DUMP_DATE", val) != 0) {
1302                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1303                     "Could not set DUMP_DATE to %s", val);
1304         } else if (!nlp->nlp_dmpnm) {
1305                 syslog(LOG_DEBUG, "No log file defined");
1306         } else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1307             nlp->nlp_tokseq, nlp->nlp_tokdate) < 0) {
1308                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1309                     "Saving backup date for \"%s\" in \"%s\".\n",
1310                     nlp->nlp_backup_path, nlp->nlp_dmpnm);
1311         }
1312 }
1313 
1314 
1315 /*
1316  * save_lbr_bk_v3
1317  *
1318  * Append the backup type and date in the DMP_NAME file for
1319  * LBR-type backup if any file is specified.
1320  *
1321  * Parameters:
1322  *   params (input) - pointer to the parameters structure
1323  *   nlp (input) - pointer to the nlp structure
1324  *
1325  * Returns:
1326  *   void
1327  */
1328 static void
1329 save_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1330 {
1331         if (!params || !nlp)
1332                 return;
1333 
1334         if (!nlp->nlp_dmpnm) {
1335                 syslog(LOG_DEBUG, "No log file defined");
1336         } else if (ndmpd_append_dumptime(nlp->nlp_dmpnm, nlp->nlp_backup_path,
1337             nlp->nlp_clevel, nlp->nlp_cdate) < 0) {
1338                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1339                     "Saving backup date for \"%s\" in \"%s\".\n",
1340                     nlp->nlp_backup_path, nlp->nlp_dmpnm);
1341         }
1342 }
1343 
1344 
1345 /*
1346  * save_level_v3
1347  *
1348  * Save the date and level of the current backup in the dumpdates
1349  * file.
1350  *
1351  * Parameters:
1352  *   params (input) - pointer to the parameters structure
1353  *   nlp (input) - pointer to the nlp structure
1354  *
1355  * Returns:
1356  *   void
1357  */
1358 static void
1359 save_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1360 {
1361         if (!params || !nlp)
1362                 return;
1363 
1364         if (!NLP_SHOULD_UPDATE(nlp)) {
1365                 syslog(LOG_DEBUG, "update not requested");
1366         } else if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1367             nlp->nlp_cdate) < 0) {
1368                 MOD_LOGV3(params, NDMP_LOG_ERROR, "Logging backup date.\n");
1369         }
1370 }
1371 
1372 
1373 /*
1374  * save_backup_date_v3
1375  *
1376  * A dispatcher function to call the corresponding save function
1377  * based on the backup type.
1378  *
1379  * Parameters:
1380  *   params (input) - pointer to the parameters structure
1381  *   nlp (input) - pointer to the nlp structure
1382  *
1383  * Returns:
1384  *   void
1385  */


1396         else if (NLP_ISSET(nlp, NLPF_LEVELBK))
1397                 save_level_v3(params, nlp);
1398         else {
1399                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1400                     "Internal error: lost backup level type for \"%s\".\n",
1401                     nlp->nlp_backup_path);
1402         }
1403 }
1404 
1405 
1406 /*
1407  * backup_alloc_structs_v3
1408  *
1409  * Create the structures for V3 backup.  This includes:
1410  *      Job stats
1411  *      Reader writer IPC
1412  *      File history callback structure
1413  *
1414  * Parameters:
1415  *   session (input) - pointer to the session


1416  *
1417  * Returns:
1418  *   0: on success
1419  *   -1: otherwise
1420  */
1421 static int
1422 backup_alloc_structs_v3(ndmpd_session_t *session)
1423 {
1424         int n;
1425         long xfer_size;
1426         ndmp_lbr_params_t *nlp;
1427         tlm_commands_t *cmds;
1428 
1429         nlp = ndmp_get_nlp(session);
1430         if (!nlp) {
1431                 syslog(LOG_ERR, "nlp == NULL");
1432                 return (-1);
1433         }
1434 
1435         nlp->nlp_jstat = tlm_new_job_stats(nlp->nlp_job_name);
1436         if (!nlp->nlp_jstat) {
1437                 syslog(LOG_ERR, "Creating job stats failed");
1438                 return (-1);
1439         }
1440 
1441         cmds = &nlp->nlp_cmds;
1442         (void) memset(cmds, 0, sizeof (*cmds));
1443 
1444         xfer_size = ndmp_buffer_get_size(session);
1445         if (xfer_size < 512*KILOBYTE) {
1446                 /*
1447                  * Read multiple of mover_record_size near to 512K.  This
1448                  * will prevent the data being copied in the mover buffer
1449                  * when we write the data.
1450                  */
1451                 n = 512 * KILOBYTE / xfer_size;
1452                 if (n <= 0)
1453                         n = 1;
1454                 xfer_size *= n;
1455                 syslog(LOG_DEBUG, "Adjusted read size: %d",
1456                     xfer_size);
1457         }
1458 
1459         cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
1460         if (!cmds->tcs_command) {
1461                 tlm_un_ref_job_stats(nlp->nlp_job_name);
1462                 return (-1);
1463         }
1464 
1465         nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
1466             ndmpd_fhpath_v3_cb, ndmpd_fhdir_v3_cb, ndmpd_fhnode_v3_cb);
1467         if (!nlp->nlp_logcallbacks) {
1468                 tlm_release_reader_writer_ipc(cmds->tcs_command);
1469                 tlm_un_ref_job_stats(nlp->nlp_job_name);
1470                 return (-1);
1471         }
1472         nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1473         nlp->nlp_restored = NULL;
1474 
1475         return (0);
1476 }
1477 
1478 
1479 /*
1480  * restore_alloc_structs_v3
1481  *
1482  * Create the structures for V3 Restore.  This includes:
1483  *      Job stats
1484  *      Reader writer IPC
1485  *      File recovery callback structure
1486  *
1487  * Parameters:
1488  *   session (input) - pointer to the session


1489  *
1490  * Returns:
1491  *   0: on success
1492  *   -1: otherwise
1493  */
1494 int
1495 restore_alloc_structs_v3(ndmpd_session_t *session)
1496 {
1497         long xfer_size;
1498         ndmp_lbr_params_t *nlp;
1499         tlm_commands_t *cmds;
1500 
1501         nlp = ndmp_get_nlp(session);
1502         if (!nlp) {
1503                 syslog(LOG_ERR, "nlp == NULL");
1504                 return (-1);
1505         }
1506 
1507         /* this is used in ndmpd_path_restored_v3() */
1508         nlp->nlp_lastidx = -1;
1509 
1510         nlp->nlp_jstat = tlm_new_job_stats(nlp->nlp_job_name);
1511         if (!nlp->nlp_jstat) {
1512                 syslog(LOG_ERR, "Creating job stats failed");
1513                 return (-1);
1514         }
1515 
1516         cmds = &nlp->nlp_cmds;
1517         (void) memset(cmds, 0, sizeof (*cmds));
1518 
1519         xfer_size = ndmp_buffer_get_size(session);
1520         cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
1521         if (!cmds->tcs_command) {
1522                 tlm_un_ref_job_stats(nlp->nlp_job_name);
1523                 return (-1);
1524         }
1525 
1526         nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
1527             ndmpd_path_restored_v3, NULL, NULL);
1528         if (!nlp->nlp_logcallbacks) {
1529                 tlm_release_reader_writer_ipc(cmds->tcs_command);
1530                 tlm_un_ref_job_stats(nlp->nlp_job_name);
1531                 return (-1);
1532         }
1533         nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
1534 
1535         nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
1536         if (nlp->nlp_rsbm < 0) {
1537                 syslog(LOG_ERR, "Out of memory.");
1538                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1539                 tlm_release_reader_writer_ipc(cmds->tcs_command);
1540                 tlm_un_ref_job_stats(nlp->nlp_job_name);
1541                 return (-1);
1542         }
1543 
1544         return (0);
1545 }
1546 
1547 
1548 /*
1549  * free_structs_v3
1550  *
1551  * Release the resources allocated by backup_alloc_structs_v3
1552  * function.
1553  *
1554  * Parameters:
1555  *   session (input) - pointer to the session


1556  *
1557  * Returns:
1558  *   void
1559  */

1560 static void
1561 free_structs_v3(ndmpd_session_t *session)
1562 {
1563         ndmp_lbr_params_t *nlp;
1564         tlm_commands_t *cmds;
1565 
1566         nlp = ndmp_get_nlp(session);
1567         if (!nlp) {
1568                 syslog(LOG_DEBUG, "nlp == NULL");
1569                 return;
1570         }
1571         cmds = &nlp->nlp_cmds;
1572         if (!cmds) {
1573                 syslog(LOG_DEBUG, "cmds == NULL");
1574                 return;
1575         }
1576 
1577         if (nlp->nlp_logcallbacks) {
1578                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
1579                 nlp->nlp_logcallbacks = NULL;
1580         } else
1581                 syslog(LOG_DEBUG, "FH CALLBACKS == NULL");
1582 
1583         if (cmds->tcs_command) {
1584                 if (cmds->tcs_command->tc_buffers != NULL)
1585                         tlm_release_reader_writer_ipc(cmds->tcs_command);
1586                 else
1587                         syslog(LOG_DEBUG, "BUFFERS == NULL");
1588                 cmds->tcs_command = NULL;
1589         } else
1590                 syslog(LOG_DEBUG, "COMMAND == NULL");
1591 
1592         if (nlp->nlp_bkmap >= 0) {
1593                 (void) dbm_free(nlp->nlp_bkmap);
1594                 nlp->nlp_bkmap = -1;
1595         }
1596 
1597         if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
1598                 if (nlp->nlp_rsbm < 0) {
1599                         syslog(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
1600                 } else {
1601                         (void) bm_free(nlp->nlp_rsbm);
1602                         nlp->nlp_rsbm = -1;
1603                 }
1604         }
1605 }
1606 
1607 
1608 /*
1609  * backup_dirv3
1610  *
1611  * Backup a directory and update the bytes processed field of the
1612  * data server.
1613  *
1614  * Parameters:
1615  *   bpp (input) - pointer to the backup parameters structure
1616  *   pnp (input) - pointer to the path node
1617  *   enp (input) - pointer to the entry node
1618  *
1619  * Returns:
1620  *   0: on success
1621  *   != 0: otherwise
1622  */
1623 static int
1624 backup_dirv3(bk_param_v3_t *bpp, fst_node_t *pnp,
1625     fst_node_t *enp)
1626 {
1627         longlong_t apos, bpos;
1628         acl_t *aclp = NULL;
1629         char *acltp;
1630         struct stat64 st;
1631         char fullpath[TLM_MAX_PATH_NAME];
1632         char *p;
1633 
1634         if (!bpp || !pnp || !enp) {
1635                 syslog(LOG_ERR, "Invalid argument in backup_dirv3");
1636                 return (-1);
1637         }
1638 


1639         if (lstat64(bpp->bp_tmp, &st) != 0)
1640                 return (0);
1641 
1642         if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1643                 syslog(LOG_DEBUG, "acl_get error errno=%d", errno);
1644                 return (-1);
1645         }
1646         if (aclp && (acltp = acl_totext(aclp,
1647             ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1648                 (void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
1649                     acltp, TLM_MAX_ACL_TXT);
1650                 acl_free(aclp);
1651                 free(acltp);
1652         } else {
1653                 *bpp->bp_tlmacl->acl_info.attr_info = '\0';
1654         }
1655 
1656         bpos = tlm_get_data_offset(bpp->bp_lcmd);
1657 
1658         p = bpp->bp_tmp + strlen(bpp->bp_chkpnm);
1659         if (*p == '/')
1660                 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
1661                     bpp->bp_unchkpnm, p);
1662         else
1663                 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",


1678 /*
1679  * backup_filev3
1680  *
1681  * Backup a file and update the bytes processed field of the
1682  * data server.
1683  *
1684  * Parameters:
1685  *   bpp (input) - pointer to the backup parameters structure
1686  *   pnp (input) - pointer to the path node
1687  *   enp (input) - pointer to the entry node
1688  *
1689  * Returns:
1690  *   0: on success
1691  *   != 0: otherwise
1692  */
1693 static int
1694 backup_filev3(bk_param_v3_t *bpp, fst_node_t *pnp,
1695     fst_node_t *enp)
1696 {
1697         char *ent;
1698         int rv = -1;
1699         longlong_t apos, bpos;
1700         acl_t *aclp = NULL;
1701         char *acltp;
1702         struct stat64 st;
1703         char fullpath[TLM_MAX_PATH_NAME];
1704         char *p;
1705 
1706         if (!bpp || !pnp || !enp) {
1707                 syslog(LOG_ERR, "Invalid argument in backup_filev3");
1708                 return (-1);
1709         }
1710 


1711         if (lstat64(bpp->bp_tmp, &st) != 0)
1712                 return (0);
1713 
1714         if (!S_ISLNK(bpp->bp_tlmacl->acl_attr.st_mode)) {
1715                 if (acl_get(bpp->bp_tmp, ACL_NO_TRIVIAL, &aclp) != 0) {
1716                         syslog(LOG_DEBUG, "acl_get error");
1717                         return (-1);
1718                 }
1719 
1720                 if (aclp &&
1721                     (acltp = acl_totext(aclp,
1722                     ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1723                         (void) strlcpy(bpp->bp_tlmacl->acl_info.attr_info,
1724                             acltp, TLM_MAX_ACL_TXT);
1725                         acl_free(aclp);
1726                         free(acltp);
1727                 } else {
1728                         *bpp->bp_tlmacl->acl_info.attr_info = '\0';
1729                 }
1730         }
1731 
1732         bpos = tlm_get_data_offset(bpp->bp_lcmd);
1733         ent = enp->tn_path ? enp->tn_path : "";
1734 
1735         p = pnp->tn_path + strlen(bpp->bp_chkpnm);
1736         if (*p == '/')


1761  *      - The bpp itself.
1762  *      - If the session pointer of the bpp is valid.
1763  *      - If the session connection to the DMA is closed.
1764  *      - If the nlp pointer of the bpp is valid.
1765  *      - If the backup is aborted.
1766  *
1767  * Parameters:
1768  *   bpp (input) - pointer to the backup parameters structure
1769  *
1770  * Returns:
1771  *   0: if everything's OK
1772  *   != 0: otherwise
1773  */
1774 static int
1775 check_bk_args(bk_param_v3_t *bpp)
1776 {
1777         int rv;
1778 
1779         if (!bpp) {
1780                 rv = -1;
1781                 syslog(LOG_DEBUG, "Lost bpp");
1782         } else if (!bpp->bp_session) {
1783                 rv = -1;
1784                 syslog(LOG_DEBUG, "Session is NULL");
1785         } else if (bpp->bp_session->ns_eof) {
1786                 rv = -1;
1787                 syslog(LOG_INFO,
1788                     "Connection client is closed for backup \"%s\"",
1789                     bpp->bp_nlp->nlp_backup_path);
1790         } else if (!bpp->bp_nlp) {
1791                 syslog(LOG_DEBUG, "Lost nlp");
1792                 return (-1);
1793         } else if (bpp->bp_session->ns_data.dd_abort) {
1794                 rv = -1;
1795                 syslog(LOG_INFO, "Backup aborted \"%s\"",
1796                     bpp->bp_nlp->nlp_backup_path);
1797         } else
1798                 rv = 0;
1799 
1800         return (rv);
1801 }
1802 
1803 
1804 /*
1805  * shouldskip
1806  *
1807  * Determines if the current entry should be skipped or it
1808  * should be backed up.
1809  *
1810  * Parameters:
1811  *   bpp (input) - pointer to the backup parameters structure
1812  *   pnp (input) - pointer to the path node
1813  *   enp (input) - pointer to the entry node
1814  *   errp (output) - pointer to the error value that should be
1815  *      returned by the caller
1816  *
1817  * Returns:
1818  *   TRUE: if the entry should not be backed up
1819  *   FALSE: otherwise
1820  */
1821 static boolean_t
1822 shouldskip(bk_param_v3_t *bpp, fst_node_t *pnp,
1823     fst_node_t *enp, int *errp)
1824 {
1825         char *ent;
1826         boolean_t rv;
1827         struct stat64 *estp;
1828 
1829         if (!bpp || !pnp || !enp || !errp) {
1830                 syslog(LOG_DEBUG, "Invalid argument in shouldskip");
1831                 return (TRUE);
1832         }
1833 
1834         if (!enp->tn_path) {
1835                 ent = "";
1836                 estp = pnp->tn_st;
1837         } else {
1838                 ent = enp->tn_path;
1839                 estp = enp->tn_st;
1840         }
1841 
1842         /*
1843          * When excluding or skipping entries, FST_SKIP should be
1844          * returned, otherwise, 0 should be returned to
1845          * get other entries in the directory of this entry.
1846          */
1847         if (!dbm_getone(bpp->bp_nlp->nlp_bkmap, (u_longlong_t)estp->st_ino)) {
1848                 rv = TRUE;
1849                 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;


1850         } else if (tlm_is_excluded(pnp->tn_path, ent, bpp->bp_excls)) {
1851                 rv = TRUE;
1852                 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;


1853         } else if (inexl(bpp->bp_nlp->nlp_exl, ent)) {
1854                 rv = TRUE;
1855                 *errp = S_ISDIR(estp->st_mode) ? FST_SKIP : 0;


1856         } else if (!S_ISDIR(estp->st_mode) &&
1857             !ininc(bpp->bp_nlp->nlp_inc, ent)) {
1858                 rv = TRUE;
1859                 *errp = 0;

1860         } else
1861                 rv = FALSE;
1862 
1863         return (rv);
1864 }
1865 
1866 
1867 /*
1868  * ischngd
1869  *
1870  * Check if the object specified should be backed up or not.
1871  * If stp belongs to a directory and if it is marked in the
1872  * bitmap vector, it shows that either the directory itself is
1873  * modified or there is something below it that will be backed
1874  * up.
1875  *
1876  * By setting ndmp_force_bk_dirs global variable to a non-zero
1877  * value, directories are backed up anyways.
1878  *
1879  * Backing up the directories unconditionally helps
1880  * restoring the metadata of directories as well, when one
1881  * of the objects below them are being restored.
1882  *
1883  * For non-directory objects, if the modification or change
1884  * time of the object is after the date specified by the
1885  * bk_selector_t, the the object must be backed up.
1886  */
1887 static boolean_t
1888 ischngd(struct stat64 *stp, time_t t, ndmp_lbr_params_t *nlp)
1889 {
1890         boolean_t rv;
1891 
1892         if (!stp) {
1893                 rv = FALSE;
1894                 syslog(LOG_DEBUG, "stp is NULL");
1895         } else if (!nlp) {
1896                 rv = FALSE;
1897                 syslog(LOG_DEBUG, "nlp is NULL");
1898         } else if (t == 0) {
1899                 /*
1900                  * if we are doing base backup then we do not need to
1901                  * check the time, for we should backup everything.
1902                  */
1903                 rv = TRUE;

1904         } else if (S_ISDIR(stp->st_mode) && ndmp_force_bk_dirs) {
1905                 rv = TRUE;

1906         } else if (S_ISDIR(stp->st_mode) &&
1907             dbm_getone(nlp->nlp_bkmap, (u_longlong_t)stp->st_ino) &&
1908             ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
1909             (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
1910                 /*
1911                  * If the object is a directory and it leads to a modified
1912                  * object (that should be backed up) and for that type of
1913                  * backup the path nodes should be backed up, then return
1914                  * TRUE.
1915                  *
1916                  * This is required by some DMAs like Backup Express, which
1917                  * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
1918                  * for the intermediate directories of a modified object.
1919                  * Other DMAs, like net_backup and net_worker, do not have such
1920                  * requirement.  This requirement makes sense for dump format
1921                  * but for 'tar' format, it does not.  In provision to the
1922                  * NDMP-v4 spec, for 'tar' format the intermediate directories
1923                  * need not to be reported.
1924                  */
1925                 rv = TRUE;

1926         } else if (stp->st_mtime > t) {
1927                 rv = TRUE;


1928         } else if (stp->st_ctime > t) {
1929                 if (NLP_IGNCTIME(nlp)) {
1930                         rv = FALSE;
1931                         syslog(LOG_DEBUG, "ign c(%lu): %lu > %lu",
1932                             (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
1933                             (uint_t)t);
1934                 } else {
1935                         rv = TRUE;
1936                         syslog(LOG_DEBUG, "c(%lu): %lu > %lu",
1937                             (uint_t)stp->st_ino, (uint_t)stp->st_ctime,
1938                             (uint_t)t);
1939                 }
1940         } else {
1941                 rv = FALSE;
1942                 syslog(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
1943                     (uint_t)stp->st_ino, (uint_t)stp->st_mtime,
1944                     (uint_t)stp->st_ctime, (uint_t)t);
1945         }
1946 
1947         return (rv);
1948 }
1949 
1950 
1951 /*
1952  * iscreated
1953  *
1954  * This function is used to check last mtime (currently inside the ACL
1955  * structure) instead of ctime for checking if the file is to be backed up
1956  * or not. See option "inc.lmtime" for more details
1957  */
1958 /*ARGSUSED*/
1959 int iscreated(ndmp_lbr_params_t *nlp, char *name, tlm_acls_t *tacl,
1960     time_t t)
1961 {
1962         int ret;
1963         acl_t *aclp = NULL;
1964         char *acltp;
1965 
1966         syslog(LOG_DEBUG, "flags %x", nlp->nlp_flags);
1967         if (NLP_INCLMTIME(nlp) == FALSE)
1968                 return (0);
1969 
1970         ret = acl_get(name, ACL_NO_TRIVIAL, &aclp);
1971         if (ret != 0) {
1972                 syslog(LOG_DEBUG,
1973                     "Error getting the acl information: err %d", ret);
1974                 return (0);
1975         }
1976         if (aclp && (acltp = acl_totext(aclp,
1977             ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
1978                 (void) strlcpy(tacl->acl_info.attr_info, acltp,
1979                     TLM_MAX_ACL_TXT);
1980                 acl_free(aclp);
1981                 free(acltp);
1982         }
1983 
1984         /* Need to add support for last mtime */
1985 
1986         return (0);
1987 }
1988 
1989 /*
1990  * size_cb
1991  *
1992  * The callback function for calculating the size of


2038         rv = check_bk_args(bpp);
2039         if (rv != 0)
2040                 return (rv);
2041 
2042         stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2043         if (shouldskip(bpp, pnp, enp, &rv))
2044                 return (rv);
2045 
2046         if (enp->tn_path) {
2047                 ent = enp->tn_path;
2048                 stp = enp->tn_st;
2049                 fhp = enp->tn_fh;
2050         } else {
2051                 ent = "";
2052                 stp = pnp->tn_st;
2053                 fhp = pnp->tn_fh;
2054         }
2055 
2056 
2057         if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
2058                 syslog(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
2059                 return (FST_SKIP);
2060         }
2061         if (NLP_ISSET(bpp->bp_nlp, NLPF_TOKENBK))
2062                 t = bpp->bp_nlp->nlp_tokdate;
2063         else if (NLP_ISSET(bpp->bp_nlp, NLPF_LEVELBK)) {
2064                 t = bpp->bp_nlp->nlp_ldate;
2065         } else {
2066                 syslog(LOG_ERR, "Unknown backup type on \"%s/%s\"",
2067                     pnp->tn_path, ent);
2068                 return (-1);
2069         }
2070 
2071         if (S_ISDIR(stp->st_mode)) {
2072                 bpp->bp_tlmacl->acl_dir_fh = *fhp;
2073                 (void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
2074                     bpp->bp_tmp, stp);
2075 
2076                 if (ischngd(stp, t, bpp->bp_nlp)) {
2077                         (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2078                             sizeof (struct stat64));
2079                         rv = backup_dirv3(bpp, pnp, enp);
2080                 }
2081         } else {
2082                 if (ischngd(stp, t, bpp->bp_nlp) ||
2083                     iscreated(bpp->bp_nlp, bpp->bp_tmp, bpp->bp_tlmacl, t)) {
2084                         rv = 0;
2085                         (void) memcpy(&bpp->bp_tlmacl->acl_attr, stp,
2086                             sizeof (struct stat64));


2123         bpp = (bk_param_v3_t *)arg;
2124         rv = check_bk_args(bpp);
2125         if (rv != 0)
2126                 return (rv);
2127 
2128         stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2129         if (shouldskip(bpp, pnp, enp, &rv))
2130                 return (rv);
2131 
2132         if (enp->tn_path) {
2133                 ent = enp->tn_path;
2134                 stp = enp->tn_st;
2135                 fhp = enp->tn_fh;
2136         } else {
2137                 ent = "";
2138                 stp = pnp->tn_st;
2139                 fhp = pnp->tn_fh;
2140         }
2141 
2142         if (!tlm_cat_path(bpp->bp_tmp, pnp->tn_path, ent)) {
2143                 syslog(LOG_ERR, "Path too long %s/%s.", pnp->tn_path, ent);
2144                 return (FST_SKIP);
2145         }
2146         if (!NLP_ISSET(bpp->bp_nlp, NLPF_LBRBK)) {
2147                 syslog(LOG_DEBUG, "!NLPF_LBRBK");
2148                 return (-1);
2149         }
2150 
2151         if (S_ISDIR(stp->st_mode)) {
2152                 bpp->bp_tlmacl->acl_dir_fh = *fhp;
2153                 (void) ndmpd_fhdir_v3_cb(bpp->bp_nlp->nlp_logcallbacks,
2154                     bpp->bp_tmp, stp);
2155 
2156                 if (SHOULD_LBRBK(bpp)) {
2157                         bpp->bp_tlmacl->acl_attr = *stp;
2158                         rv = backup_dirv3(bpp, pnp, enp);
2159                 }
2160         } else if (SHOULD_LBRBK(bpp)) {
2161                 rv = 0;
2162                 bpp->bp_tlmacl->acl_attr = *stp;
2163                 bpp->bp_tlmacl->acl_fil_fh = *fhp;
2164                 (void) backup_filev3(bpp, pnp, enp);
2165         }
2166 
2167         return (rv);
2168 }
2169 
2170 
2171 /*
2172  * backup_reader_v3
2173  *
2174  * The reader thread for the backup.  It sets up the callback
2175  * parameters and traverses the backup hierarchy in level-order
2176  * way.
2177  *
2178  * Parameters:
2179  *   argp (input) - backup reader argument



2180  *
2181  * Returns:
2182  *   0: on success
2183  *   != 0: otherwise
2184  */
2185 static int
2186 backup_reader_v3(backup_reader_arg_t *argp)
2187 {
2188         int rv;
2189         tlm_cmd_t *lcmd;
2190         tlm_acls_t tlm_acls;
2191         longlong_t bpos, n;
2192         bk_param_v3_t bp;
2193         fs_traverse_t ft;

2194         ndmp_lbr_params_t *nlp;
2195         tlm_commands_t *cmds;
2196         int rc;
2197 
2198         if (!argp)
2199                 return (-1);
2200 

2201         nlp = argp->br_nlp;
2202         cmds = argp->br_cmds;
2203 
2204         rv = 0;
2205         lcmd = cmds->tcs_command;
2206         lcmd->tc_ref++;
2207         cmds->tcs_reader_count++;
2208 
2209         (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
2210 
2211         /* NDMP parameters */
2212         bp.bp_session = nlp->nlp_session;
2213         bp.bp_nlp = nlp;
2214 
2215         /* LBR-related parameters  */
2216         bp.bp_js = tlm_ref_job_stats(nlp->nlp_job_name);
2217         bp.bp_cmds = cmds;
2218         bp.bp_lcmd = lcmd;
2219         bp.bp_tlmacl = &tlm_acls;
2220         bp.bp_opr = 0;
2221 
2222         /* release the parent thread, after referencing the job stats */
2223         rc = pthread_barrier_wait(&argp->br_barrier);
2224         if (rc == PTHREAD_BARRIER_SERIAL_THREAD) {
2225                 (void) pthread_barrier_destroy(&argp->br_barrier);
2226         }
2227 
2228         bp.bp_tmp = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2229         if (!bp.bp_tmp)
2230                 return (-1);
2231 
2232         /*
2233          * Make the checkpointed paths for traversing the
2234          * backup hierarchy, if we make the checkpoint.
2235          */
2236         bp.bp_unchkpnm = nlp->nlp_backup_path;
2237         if (!NLP_ISCHKPNTED(nlp)) {
2238                 tlm_acls.acl_checkpointed = FALSE;
2239                 bp.bp_chkpnm = ndmp_malloc(sizeof (char) * TLM_MAX_PATH_NAME);
2240                 if (!bp.bp_chkpnm) {
2241                         NDMP_FREE(bp.bp_tmp);
2242                         return (-1);
2243                 }
2244                 (void) tlm_build_snapshot_name(nlp->nlp_backup_path,
2245                     bp.bp_chkpnm, nlp->nlp_jstat->js_job_name);
2246         } else {
2247                 tlm_acls.acl_checkpointed = TRUE;
2248                 bp.bp_chkpnm = nlp->nlp_mountpoint;
2249         }
2250         bp.bp_excls = ndmpd_make_exc_list();
2251 
2252         /* set traversing arguments */
2253         ft.ft_path = nlp->nlp_backup_path;
2254         ft.ft_lpath = bp.bp_chkpnm;
2255 

2256         if (NLP_ISSET(nlp, NLPF_TOKENBK) || NLP_ISSET(nlp, NLPF_LEVELBK)) {
2257                 ft.ft_callbk = timebk_v3;
2258                 tlm_acls.acl_clear_archive = FALSE;
2259         } else if (NLP_ISSET(nlp, NLPF_LBRBK)) {
2260                 ft.ft_callbk = lbrbk_v3;
2261                 tlm_acls.acl_clear_archive = FALSE;
2262 
2263                 syslog(LOG_DEBUG, "bp_opr %x clr_arc %c",
2264                     bp.bp_opr, NDMP_YORN(tlm_acls.acl_clear_archive));
2265         } else {
2266                 rv = -1;
2267                 MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2268                     "Unknown backup type.\n");
2269         }
2270 
2271         ft.ft_arg = &bp;
2272         ft.ft_logfp = (ft_log_t)syslog;
2273         ft.ft_flags = FST_VERBOSE | FST_STOP_ONERR;
2274 
2275         syslog(LOG_DEBUG, "Traverse logical path [%s]", ft.ft_lpath);
2276 
2277         /* take into account the header written to the stream so far */
2278         n = tlm_get_data_offset(lcmd);
2279         nlp->nlp_session->ns_data.dd_module.dm_stats.ms_bytes_processed = n;
2280 
2281         if (rv == 0) {
2282                 /* start traversing the hierarchy and actual backup */
2283                 rv = traverse_level(&ft);
2284                 if (rv == 0) {
2285                         /* write the trailer and update the bytes processed */
2286                         bpos = tlm_get_data_offset(lcmd);
2287                         (void) write_tar_eof(lcmd);
2288                         n = tlm_get_data_offset(lcmd) - bpos;
2289                         nlp->nlp_session->
2290                             ns_data.dd_module.dm_stats.ms_bytes_processed += n;
2291                 } else {
2292                         MOD_LOGV3(nlp->nlp_params, NDMP_LOG_ERROR,
2293                             "Filesystem traverse error.\n");
2294                         ndmpd_data_error(nlp->nlp_session,
2295                             NDMP_DATA_HALT_INTERNAL_ERROR);
2296                 }
2297         }
2298 
2299         if (!NLP_ISCHKPNTED(nlp))
2300                 NDMP_FREE(bp.bp_chkpnm);
2301         NDMP_FREE(bp.bp_tmp);
2302         NDMP_FREE(bp.bp_excls);
2303 
2304         cmds->tcs_reader_count--;
2305         lcmd->tc_writer = TLM_STOP;
2306         tlm_release_reader_writer_ipc(lcmd);
2307         tlm_un_ref_job_stats(nlp->nlp_job_name);

2308 
2309         return (rv);
2310 }
2311 
2312 
2313 /*
2314  * tar_backup_v3
2315  *
2316  * Traverse the backup hierarchy if needed and make the bitmap.
2317  * Then launch reader and writer threads to do the actual backup.
2318  *
2319  * Parameters:
2320  *   session (input) - pointer to the session
2321  *   params (input) - pointer to the parameters structure
2322  *   nlp (input) - pointer to the nlp structure

2323  *
2324  * Returns:
2325  *   0: on success
2326  *   != 0: otherwise
2327  */
2328 static int
2329 tar_backup_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2330     ndmp_lbr_params_t *nlp)
2331 {
2332         tlm_commands_t *cmds;
2333         backup_reader_arg_t arg;
2334         pthread_t rdtp;
2335         char info[256];
2336         int result;
2337         ndmp_context_t nctx;
2338         int err;
2339         int rc;
2340 
2341         if (ndmp_get_bk_dir_ino(nlp)) {
2342                 syslog(LOG_ERR, "Couldn't get backup directory inode");
2343                 return (-1);
2344         }
2345 
2346         result = err = 0;
2347 
2348         /* exit as if there was an internal error */
2349         if (session->ns_eof) {
2350                 return (-1);
2351         }
2352         if (!session->ns_data.dd_abort) {
2353                 if (backup_alloc_structs_v3(session) < 0) {
2354                         nlp->nlp_bkmap = -1;
2355                         return (-1);
2356                 }
2357 
2358                 if (ndmpd_mark_inodes_v3(session, nlp) != 0) {
2359                         if (nlp->nlp_bkmap != -1) {
2360                                 (void) dbm_free(nlp->nlp_bkmap);
2361                                 nlp->nlp_bkmap = -1;
2362                         }
2363                         free_structs_v3(session);
2364                         return (-1);
2365                 }
2366 
2367                 nlp->nlp_jstat->js_start_ltime = time(NULL);
2368                 nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
2369                 nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
2370 
2371                 cmds = &nlp->nlp_cmds;
2372                 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
2373                 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
2374                 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
2375 
2376                 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
2377                         free_structs_v3(session);
2378                         return (-1);
2379                 }
2380 
2381                 syslog(LOG_DEBUG, "Backing up \"%s\" started.",
2382                     NLP_ISCHKPNTED(nlp)
2383                     ? nlp->nlp_mountpoint : nlp->nlp_backup_path);
2384 
2385                 /* Plug-in module */
2386                 if (ndmp_pl != NULL &&
2387                     ndmp_pl->np_pre_backup != NULL) {
2388                         (void) memset(&nctx, 0, sizeof (ndmp_context_t));
2389                         nctx.nc_plversion = ndmp_pl->np_plversion;
2390                         nctx.nc_plname = ndmpd_get_prop(NDMP_PLUGIN_PATH);
2391                         nctx.nc_cmds = cmds;
2392                         nctx.nc_params = params;
2393                         nctx.nc_ddata = (void *) session;
2394                         if ((err = ndmp_pl->np_pre_backup(ndmp_pl, &nctx,
2395                             nlp->nlp_backup_path)) != 0) {
2396                                 syslog(LOG_ERR, "Pre-backup plug-in: %m");
2397                                 goto backup_out;
2398                         }
2399                 }
2400 
2401                 (void) memset(&arg, 0, sizeof (backup_reader_arg_t));

2402                 arg.br_nlp = nlp;
2403                 arg.br_cmds = cmds;
2404 
2405                 (void) pthread_barrier_init(&arg.br_barrier, 0, 2);
2406 
2407                 err = pthread_create(&rdtp, NULL, (funct_t)backup_reader_v3,
2408                     (void *)&arg);
2409                 if (err == 0) {
2410                         rc =  pthread_barrier_wait(&arg.br_barrier);
2411                         if (rc == PTHREAD_BARRIER_SERIAL_THREAD) {
2412                                 (void) pthread_barrier_destroy(&arg.br_barrier);
2413                         }
2414                 } else {
2415                         (void) pthread_barrier_destroy(&arg.br_barrier);
2416                         free_structs_v3(session);
2417                         syslog(LOG_ERR, "Launch backup_reader_v3 failed on %s",
2418                             nlp->nlp_job_name);
2419                         return (-1);
2420                 }
2421 
2422                 if ((err = ndmp_tar_writer(session, params, cmds)) != 0)
2423                         result = EIO;
2424 
2425                 nlp->nlp_jstat->js_stop_time = time(NULL);
2426 
2427                 (void) snprintf(info, sizeof (info),
2428                     "Runtime [%s] %lu bytes (%lu): %d seconds\n",
2429                     nlp->nlp_backup_path,
2430                     session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2431                     session->ns_data.dd_module.dm_stats.ms_bytes_processed,
2432                     nlp->nlp_jstat->js_stop_time -
2433                     nlp->nlp_jstat->js_start_ltime);
2434                 MOD_LOGV3(params, NDMP_LOG_NORMAL, info);
2435 
2436                 ndmp_wait_for_reader(cmds);
2437                 (void) pthread_join(rdtp, NULL);

2438                 /* exit as if there was an internal error */
2439                 if (session->ns_eof) {
2440                         result = EPIPE;
2441                         err = -1;
2442                 }
2443                 if (!session->ns_data.dd_abort) {
2444                         ndmpd_audit_backup(session->ns_connection,
2445                             nlp->nlp_backup_path,
2446                             session->ns_data.dd_data_addr.addr_type,
2447                             session->ns_tape.td_adapter_name, result);
2448                         syslog(LOG_DEBUG, "Backing up \"%s\" Finished.",
2449                             NLP_ISCHKPNTED(nlp) ?
2450                             nlp->nlp_mountpoint : nlp->nlp_backup_path);
2451                 }
2452         }
2453 
2454         if (session->ns_data.dd_abort) {
2455                 ndmpd_audit_backup(session->ns_connection,
2456                     nlp->nlp_backup_path,
2457                     session->ns_data.dd_data_addr.addr_type,
2458                     session->ns_tape.td_adapter_name, EINTR);
2459                 syslog(LOG_INFO, "Backing up \"%s\" aborted.",
2460                     NLP_ISCHKPNTED(nlp) ?
2461                     nlp->nlp_mountpoint : nlp->nlp_backup_path);
2462                 err = -1;
2463         } else {
2464 
2465 backup_out:
2466                 /* Plug-in module */
2467                 if (ndmp_pl != NULL &&
2468                     ndmp_pl->np_post_backup != NULL &&
2469                     ndmp_pl->np_post_backup(ndmp_pl, &nctx, err) == -1) {
2470                         syslog(LOG_ERR, "Post-backup plug-in: %m");
2471                         return (-1);
2472                 }
2473         }
2474 
2475         free_structs_v3(session);
2476         return (err);
2477 }
2478 
2479 /*
2480  * get_backup_size
2481  *
2482  * Find the estimate of backup size. This is used to get an estimate
2483  * of the progress of backup during NDMP backup.
2484  */
2485 void
2486 get_backup_size(ndmp_lbr_params_t *nlp)
2487 {
2488         fs_traverse_t ft;
2489         u_longlong_t bk_size = 0;
2490         char buf[256];
2491         char spath[PATH_MAX];
2492         int rv;
2493 
2494         if (NLP_ISCHKPNTED(nlp)) {
2495                 ft.ft_path = nlp->nlp_mountpoint;

2496         } else {
2497                 (void) tlm_build_snapshot_name(nlp->nlp_backup_path,
2498                     spath, nlp->nlp_job_name);
2499                 ft.ft_path = spath;
2500         }
2501 
2502         ft.ft_lpath = ft.ft_path;
2503         ft.ft_callbk = size_cb;
2504         ft.ft_arg = &bk_size;
2505         ft.ft_logfp = (ft_log_t)syslog;
2506         ft.ft_flags = FST_VERBOSE;
2507 
2508         if ((rv = traverse_level(&ft)) != 0) {
2509                 syslog(LOG_DEBUG, "bksize err=%d", rv);
2510                 syslog(LOG_DEBUG, "[%s] backup will be reported as [0]\n",
2511                     nlp->nlp_job_name, buf);
2512                 bk_size = 0;
2513         } else {
2514                 (void) zfs_nicenum(bk_size, buf, sizeof (buf));
2515                 syslog(LOG_DEBUG, "[%s] backup size is [%s]\n",
2516                     nlp->nlp_job_name, buf);
2517         }
2518 
2519         nlp->nlp_session->ns_data.dd_data_size = bk_size;
2520 }
2521 
2522 /*
2523  * get_rs_path_v3
2524  *
2525  * Find the restore path
2526  */
2527 ndmp_error
2528 get_rs_path_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2529 {
2530         char *dp;
2531         ndmp_error rv = -1;
2532         mem_ndmp_name_v3_t *ep;
2533         int i, nm_cnt;
2534         char *nm_dpath_list[MULTIPLE_DEST_DIRS];
2535         static char mdest_buf[256];
2536 
2537         *mdest_buf = 0;
2538         *nm_dpath_list = "";
2539         for (i = 0, nm_cnt = 0; i < (int)nlp->nlp_nfiles; i++) {
2540                 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2541                 if (!ep) {
2542                         syslog(LOG_ERR, "Can't get Nlist[%d]", i);
2543                         return (NDMP_ILLEGAL_ARGS_ERR);
2544                 }
2545                 if (strcmp(nm_dpath_list[nm_cnt], ep->nm3_dpath) != 0 &&
2546                     nm_cnt < MULTIPLE_DEST_DIRS - 1)
2547                         nm_dpath_list[++nm_cnt] = ep->nm3_dpath;
2548         }
2549 
2550         multiple_dest_restore = (nm_cnt > 1);
2551         nlp->nlp_restore_path = mdest_buf;
2552 
2553         for (i = 1; i < nm_cnt + 1; i++) {
2554                 if (ISDEFINED(nm_dpath_list[i]))
2555                         dp = nm_dpath_list[i];
2556                 else
2557                         /* the default destination path is backup directory */
2558                         dp = nlp->nlp_backup_path;
2559 
2560                 /* check the destination directory exists and is writable */
2561                 if (!fs_volexist(dp)) {
2562                         rv = NDMP_ILLEGAL_ARGS_ERR;
2563                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2564                             "Invalid destination path volume \"%s\".\n", dp);
2565                 } else if (!voliswr(dp)) {
2566                         rv = NDMP_ILLEGAL_ARGS_ERR;
2567                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2568                             "The destination path volume"
2569                             " is not writable \"%s\".\n", dp);
2570                 } else {
2571                         rv = NDMP_NO_ERR;
2572                         (void) strlcat(nlp->nlp_restore_path, dp,
2573                             sizeof (mdest_buf));
2574                         syslog(LOG_DEBUG, "rspath: \"%s\"", dp);
2575                 }
2576 
2577                 /*
2578                  * Exit if there is an error or it is not a multiple
2579                  * destination restore mode
2580                  */
2581                 if (rv != NDMP_NO_ERR || !multiple_dest_restore)
2582                         break;
2583 
2584                 if (i < nm_cnt)
2585                         (void) strlcat(nlp->nlp_restore_path, ", ",
2586                             sizeof (mdest_buf));
2587         }
2588 
2589         return (rv);
2590 }
2591 
2592 
2593 /*
2594  * fix_nlist_v3


2724                 bp = joinpath(buf, nlp->nlp_backup_path, ep->nm3_opath);
2725                 if (!bp) {
2726                         /*
2727                          * Note: The same problem of above with long path.
2728                          */
2729                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2730                             "Path too long(%s/%s)",
2731                             nlp->nlp_backup_path, ep->nm3_opath);
2732                         continue;
2733                 }
2734                 cp = strdup(bp);
2735                 if (!cp) {
2736                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2737                             "Insufficient memory.\n");
2738                         rv = NDMP_NO_MEM_ERR;
2739                         break;
2740                 }
2741                 NDMP_FREE(ep->nm3_opath);
2742                 ep->nm3_opath = cp;
2743 
2744                 syslog(LOG_DEBUG, "orig[%d]: \"%s\"", i, ep->nm3_opath);
2745                 if (ep->nm3_dpath) {
2746                         syslog(LOG_DEBUG,
2747                             "dest[%d]: \"%s\"", i, ep->nm3_dpath);
2748                 } else {
2749                         syslog(LOG_INFO, "dest[%d]: \"%s\"", i, "NULL");
2750                 }
2751         }
2752 
2753         free(buf);
2754 
2755         return (rv);
2756 }
2757 
2758 
2759 /*
2760  * allvalidfh
2761  *
2762  * Run a sanity check on the file history info. The file history
2763  * info is the offset of the record starting the entry on the tape
2764  * and is used in DAR (direct access restore mode).
2765  */
2766 static boolean_t
2767 allvalidfh(ndmpd_session_t *session, ndmpd_module_params_t *params)
2768 {
2769         int i, n;


2824 
2825         if (NLP_ISSET(nlp, NLPF_DIRECT))
2826                 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2827                     "Direct Access Restore.\n");
2828 }
2829 
2830 
2831 /*
2832  * send_unrecovered_list_v3
2833  *
2834  * Create the list of files that were in restore list but
2835  * not recovered due to some errors.
2836  */
2837 int
2838 send_unrecovered_list_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
2839 {
2840         int i, rv;
2841         int err;
2842 
2843         if (!params) {
2844                 syslog(LOG_ERR, "params == NULL");
2845                 return (-1);
2846         }
2847         if (!nlp) {
2848                 syslog(LOG_ERR, "nlp == NULL");
2849                 return (-1);
2850         }
2851 
2852         if (nlp->nlp_lastidx != -1) {
2853                 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)nlp->nlp_lastidx))
2854                         err = ENOENT;
2855                 else
2856                         err = 0;
2857                 (void) ndmp_send_recovery_stat_v3(params, nlp,
2858                     nlp->nlp_lastidx, err);
2859                 nlp->nlp_lastidx = -1;
2860         }
2861 
2862         rv = 0;
2863         for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
2864                 if (!bm_getone(nlp->nlp_rsbm, (u_longlong_t)i)) {
2865                         rv = ndmp_send_recovery_stat_v3(params, nlp, i, ENOENT);
2866                         if (rv < 0)
2867                                 break;
2868                 }
2869         }
2870 
2871         return (rv);
2872 }
2873 
2874 
2875 
2876 /*
2877  * restore_dar_alloc_structs_v3
2878  *
2879  * Allocates the necessary structures for running DAR restore.
2880  * It just creates the reader writer IPC.
2881  * This function is called for each entry in the restore entry list.
2882  *
2883  * Parameters:
2884  *   session (input) - pointer to the session

2885  *
2886  * Returns:
2887  *    0: on success
2888  *   -1: on error
2889  */
2890 int
2891 restore_dar_alloc_structs_v3(ndmpd_session_t *session)
2892 {
2893         long xfer_size;
2894         ndmp_lbr_params_t *nlp;
2895         tlm_commands_t *cmds;
2896 
2897         nlp = ndmp_get_nlp(session);
2898         if (!nlp) {
2899                 syslog(LOG_ERR, "nlp == NULL");
2900                 return (-1);
2901         }
2902 
2903         cmds = &nlp->nlp_cmds;
2904         (void) memset(cmds, 0, sizeof (*cmds));
2905 
2906         xfer_size = ndmp_buffer_get_size(session);
2907         cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
2908         if (!cmds->tcs_command) {
2909                 tlm_un_ref_job_stats(nlp->nlp_job_name);
2910                 return (-1);
2911         }
2912 
2913         return (0);
2914 }
2915 
2916 
2917 /*
2918  * free_dar_structs_v3
2919  *
2920  * To free the structures were created by restore_dar_alloc_structs_v3.
2921  * This funnction is called for each entry in restore entry list.
2922  *
2923  * Parameters:
2924  *   session (input) - pointer to the session

2925  *
2926  * Returns:
2927  *      NONE
2928  */
2929 /*ARGSUSED*/
2930 static void
2931 free_dar_structs_v3(ndmpd_session_t *session)
2932 {
2933         ndmp_lbr_params_t *nlp;
2934         tlm_commands_t *cmds;
2935 
2936         nlp = ndmp_get_nlp(session);
2937         if (!nlp) {
2938                 syslog(LOG_DEBUG, "nlp == NULL");
2939                 return;
2940         }
2941         cmds = &nlp->nlp_cmds;
2942         if (!cmds) {
2943                 syslog(LOG_DEBUG, "cmds == NULL");
2944                 return;
2945         }
2946 
2947         if (cmds->tcs_command) {
2948                 if (cmds->tcs_command->tc_buffers != NULL)
2949                         tlm_release_reader_writer_ipc(cmds->tcs_command);
2950                 else
2951                         syslog(LOG_DEBUG, "BUFFERS == NULL");
2952                 cmds->tcs_command = NULL;
2953         } else
2954                 syslog(LOG_DEBUG, "COMMAND == NULL");
2955 }
2956 
2957 
2958 /*
2959  * ndmp_dar_tar_init_v3
2960  *
2961  * Constructor for the DAR restore. Creates job name, allocates structures
2962  * needed for keeping the statistics, and reports the start of restore action.
2963  * It is called once for each DAR restore request.
2964  *
2965  * Parameters:
2966  *   session (input) - pointer to the session
2967  *   nlp (input) - pointer to the nlp structure
2968  *
2969  * Returns:
2970  *   char pointer: on success
2971  *   NULL: on error
2972  */
2973 static char *ndmpd_dar_tar_init_v3(ndmpd_session_t *session,
2974     ndmp_lbr_params_t *nlp)
2975 {
2976         char *jname;
2977 
2978         jname = ndmp_malloc(TLM_MAX_BACKUP_JOB_NAME);
2979 
2980         if (!jname)
2981                 return (NULL);
2982 
2983         if (ndmp_new_job_name(jname, TLM_MAX_BACKUP_JOB_NAME) <= 0) {
2984                 free(jname);
2985                 return (NULL);
2986         }
2987 
2988         if (!nlp) {
2989                 free(jname);
2990                 syslog(LOG_DEBUG, "nlp == NULL");
2991                 return (NULL);
2992         }
2993 
2994         nlp->nlp_jstat = tlm_new_job_stats(jname);
2995         if (!nlp->nlp_jstat) {
2996                 free(jname);
2997                 syslog(LOG_DEBUG, "Creating job stats");
2998                 return (NULL);
2999         }
3000 
3001         nlp->nlp_jstat->js_start_ltime = time(NULL);
3002         nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3003 
3004         nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
3005             ndmpd_path_restored_v3, NULL, NULL);
3006         if (!nlp->nlp_logcallbacks) {
3007                 tlm_un_ref_job_stats(jname);
3008                 free(jname);
3009                 return (NULL);
3010         }
3011         nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
3012 
3013         nlp->nlp_rsbm = bm_alloc(nlp->nlp_nfiles, 0);
3014         if (nlp->nlp_rsbm < 0) {
3015                 syslog(LOG_ERR, "Out of memory.");
3016                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3017                 tlm_un_ref_job_stats(jname);
3018                 free(jname);
3019                 return (NULL);
3020         }
3021 
3022         /* this is used in ndmpd_path_restored_v3() */
3023         nlp->nlp_lastidx = -1;
3024 
3025         syslog(LOG_DEBUG, "Restoring from %s tape(s).",
3026             ndmp_data_get_mover_mode(session));
3027 
3028         return (jname);
3029 }
3030 
3031 /*
3032  * ndmpd_dar_tar_end_v3
3033  *
3034  * Deconstructor for the DAR restore. This function is called once per
3035  * DAR request. It deallocates memories allocated by ndmpd_dar_tar_init_v3.
3036  *
3037  * Parameters:
3038  *   session (input) - pointer to the session
3039  *   params (input) - pointer to the parameters structure
3040  *   nlp (input) - pointer to the nlp structure
3041  *   jname(input) - job name
3042  *
3043  * Returns:
3044  *   0: on success
3045  *   -1: on error
3046  */
3047 static int ndmpd_dar_tar_end_v3(ndmpd_session_t *session,
3048     ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *jname)
3049 {
3050         int err = 0;
3051 
3052 
3053         syslog(LOG_DEBUG, "lastidx %d", nlp->nlp_lastidx);
3054 
3055         /* nothing restored. */
3056         (void) send_unrecovered_list_v3(params, nlp);
3057 
3058         if (nlp->nlp_jstat) {
3059                 nlp->nlp_bytes_total =
3060                     (u_longlong_t)nlp->nlp_jstat->js_bytes_total;
3061                 tlm_un_ref_job_stats(jname);
3062                 nlp->nlp_jstat = NULL;
3063         } else {
3064                 syslog(LOG_DEBUG, "JSTAT == NULL");
3065         }
3066 
3067         if (nlp->nlp_logcallbacks) {
3068                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
3069                 nlp->nlp_logcallbacks = NULL;
3070         } else {
3071                 syslog(LOG_DEBUG, "FH CALLBACKS == NULL");
3072         }
3073 
3074         if (session->ns_data.dd_abort) {
3075                 syslog(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3076                     (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3077                 err = EINTR;
3078         } else {
3079                 syslog(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3080                     (nlp->nlp_restore_path) ? nlp->nlp_restore_path :
3081                     "NULL", err);
3082         }
3083 
3084         if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER) {
3085                 if (nlp->nlp_rsbm < 0) {
3086                         syslog(LOG_DEBUG, "nlp_rsbm < 0 %d", nlp->nlp_rsbm);
3087                 } else {
3088                         (void) bm_free(nlp->nlp_rsbm);
3089                         nlp->nlp_rsbm = -1;
3090                 }
3091         }
3092 
3093         free(jname);
3094 
3095         return (err);
3096 }
3097 
3098 
3099 /*
3100  * ndmpd_dar_tar_v3
3101  *
3102  * This function is called for each entry in DAR entry list. The window
3103  * is already located and we should be in the right position to read
3104  * the data from the tape.
3105  * For each entry we setup selection list; so that, if the file name from
3106  * tape is not as the name client asked for, error be returned.
3107  *
3108  * Parameters:
3109  *   session (input) - pointer to the session
3110  *   params (input) - pointer to the parameters structure
3111  *   nlp (input) - pointer to the nlp structure

3112  *   dar_index(input) - Index of this entry in the restore list
3113  *
3114  * Returns:
3115  *   0: on success
3116  *   -1: on error
3117  */
3118 static int
3119 ndmpd_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3120     ndmp_lbr_params_t *nlp, int dar_index)
3121 {
3122         char *excl;
3123         char **sels;
3124         int flags;
3125         int err;
3126         tlm_commands_t *cmds;
3127         struct rs_name_maker rn;
3128         int data_addr_type = session->ns_data.dd_data_addr.addr_type;
3129         ndmp_tar_reader_arg_t arg;
3130         pthread_t rdtp;
3131         ndmp_context_t nctx;
3132         mem_ndmp_name_v3_t *ep;
3133 
3134         err = 0;
3135 
3136         /*
3137          * We have to allocate and deallocate buffers every time we
3138          * run the restore, for we need to flush the buffers.
3139          */
3140         if (restore_dar_alloc_structs_v3(session) < 0)
3141                 return (-1);
3142 
3143         sels = setupsels(session, params, nlp, dar_index);
3144         if (!sels) {
3145                 free_dar_structs_v3(session);
3146                 return (-1);
3147         }
3148         excl = NULL;
3149         flags = RSFLG_OVR_ALWAYS;
3150         rn.rn_nlp = nlp;
3151         rn.rn_fp = mknewname;
3152 
3153         if (!session->ns_data.dd_abort) {
3154                 cmds = &nlp->nlp_cmds;
3155                 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3156                 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3157                 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3158 
3159                 arg.tr_session = session;
3160                 arg.tr_mod_params = params;
3161                 arg.tr_cmds = cmds;
3162 
3163                 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3164                     (void *)&arg);
3165                 if (err == 0) {
3166                         tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3167                 } else {
3168                         syslog(LOG_ERR, "launch ndmp_tar_reader failed");
3169                         return (-1);
3170                 }
3171 
3172                 cmds->tcs_command->tc_ref++;
3173                 cmds->tcs_writer_count++;
3174 
3175                 /* Plug-in module */
3176                 if (ndmp_pl != NULL &&
3177                     ndmp_pl->np_pre_restore != NULL) {
3178                         (void) memset(&nctx, 0, sizeof (ndmp_context_t));
3179                         nctx.nc_cmds = cmds;
3180                         nctx.nc_params = params;
3181                         nctx.nc_ddata = (void *) session;
3182                         ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params,
3183                             dar_index - 1);
3184 
3185                         if ((err = ndmp_pl->np_pre_restore(ndmp_pl, &nctx,
3186                             ep->nm3_opath, ep->nm3_dpath))
3187                             != 0) {
3188                                 syslog(LOG_ERR, "Pre-restore plug-in: %m");
3189                                 ndmp_stop_local_reader(session, cmds);
3190                                 ndmp_wait_for_reader(cmds);
3191                                 (void) pthread_join(rdtp, NULL);
3192                                 ndmp_stop_remote_reader(session);
3193                                 goto restore_out;
3194                         }
3195                 }
3196 
3197                 if (tm_tar_ops.tm_getdir != NULL) {
3198                         char errbuf[256];
3199 
3200                         err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3201                             nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags,
3202                             dar_index, nlp->nlp_mountpoint,
3203                             session->hardlink_q);
3204                         /*
3205                          * If the fatal error from tm_getdir looks like an
3206                          * errno code, we send the error description to DMA.
3207                          */
3208                         if (err > 0 && strerror_r(err, errbuf,
3209                             sizeof (errbuf)) == 0) {
3210                                 MOD_LOGV3(params, NDMP_LOG_ERROR,
3211                                     "Fatal error during the restore: %s\n",
3212                                     errbuf);
3213                         }
3214                 }
3215 
3216                 cmds->tcs_writer_count--;
3217                 cmds->tcs_command->tc_ref--;
3218                 syslog(LOG_DEBUG, "stop local reader.");
3219                 ndmp_stop_local_reader(session, cmds);
3220 
3221                 ndmp_wait_for_reader(cmds);
3222                 (void) pthread_join(rdtp, NULL);
3223 
3224                 /*
3225                  * If this is the last DAR entry and it is a three-way
3226                  * restore then we should close the connection.
3227                  */
3228                 if ((data_addr_type == NDMP_ADDR_TCP) &&
3229                     (dar_index == (int)session->ns_data.dd_nlist_len)) {
3230                         syslog(LOG_DEBUG, "stop remote reader.");
3231                         ndmp_stop_remote_reader(session);
3232                 }
3233 
3234                 /* exit as if there was an internal error */
3235                 if (session->ns_eof)
3236                         err = -1;
3237 restore_out:
3238                 /* Plug-in module */
3239                 if (ndmp_pl != NULL &&
3240                     ndmp_pl->np_post_restore != NULL &&
3241                     ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3242                         syslog(LOG_DEBUG, "Post-restore plug-in: %m");
3243                         err = -1;
3244                 }
3245         }
3246 
3247         NDMP_FREE(sels);
3248 
3249         free_dar_structs_v3(session);
3250 
3251         return (err);
3252 }
3253 
3254 /*
3255  * ndmpd_dar_locate_windwos_v3
3256  *
3257  * Locating the right window in which the requested file is backed up.
3258  * We should go through windows to find the exact location, for the
3259  * file can be located in for example 10th window after the current window.
3260  *
3261  * Parameters:
3262  *   session (input) - pointer to the session
3263  *   params (input) - pointer to the parameters structure
3264  *   fh_info (input) - index from the beginning of the backup stream
3265  *   len (input) - Length of the mover window
3266  *
3267  * Returns:
3268  *   0: on success
3269  *   -1: on error
3270  */
3271 static int
3272 ndmpd_dar_locate_window_v3(ndmpd_session_t *session,
3273     ndmpd_module_params_t *params, u_longlong_t fh_info, u_longlong_t len)
3274 {
3275         int ret = 0;
3276 
3277 
3278         for (; ; ) {
3279                 ret = (*params->mp_seek_func)(session, fh_info, len);
3280 
3281                 syslog(LOG_DEBUG, "ret %d", ret);
3282                 if (ret == 0) /* Seek was done successfully */
3283                         break;
3284                 else if (ret < 0) {
3285                         syslog(LOG_ERR,
3286                             "Seek error in ndmpd_dar_locate_window_v3");
3287                         break;
3288                 }
3289 
3290                 /*
3291                  * DMA moved to a new window.
3292                  * If we are reading the remainig of the file from
3293                  * new window, seek is handled by ndmpd_local_read_v3.
3294                  * Here we should continue the seek inside the new
3295                  * window.
3296                  */
3297                 continue;
3298         }
3299         return (ret);
3300 }
3301 
3302 /*
3303  * ndmpd_rs_dar_tar_v3
3304  *
3305  * Main DAR function. It calls the constructor, then for each entry it
3306  * calls the locate_window_v3 to find the exact position of the file. Then


3327         int n = session->ns_data.dd_nlist_len;
3328         int i, ret = 0;
3329         int result = 0;
3330 
3331         jname = ndmpd_dar_tar_init_v3(session, nlp);
3332 
3333         if (!jname)
3334                 return (-1);
3335 
3336         /*
3337          * We set the length = sizeof (tlm_tar_hdr_t)
3338          * This is important for three-way DAR restore, for we should
3339          * read the header first (If we ask for more data then we have
3340          * to read and discard the remaining data in the socket)
3341          */
3342         len = tlm_tarhdr_size();
3343 
3344         for (i = 0; i < n; ++i) {
3345                 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
3346                 if (!ep) {
3347                         syslog(LOG_DEBUG, "ep NULL, i %d", i);
3348                         continue;
3349                 }
3350                 syslog(LOG_DEBUG,
3351                     "restoring opath %s, dpath %s, fh_info %lld",
3352                     ep->nm3_opath ? ep->nm3_opath : "NULL",
3353                     ep->nm3_dpath ? ep->nm3_dpath : "NULL",
3354                     ep->nm3_fh_info);
3355 
3356                 /*
3357                  * We should seek till finding the window in which file
3358                  * is located.
3359                  */
3360                 ret = ndmpd_dar_locate_window_v3(session, params,
3361                     ep->nm3_fh_info, len);
3362 
3363                 if (ret < 0) /* If seek fails, restore should be aborted */
3364                         break;
3365                 /*
3366                  * We are inside the target window.
3367                  * for each restore we will use one entry as selection list
3368                  */
3369                 if ((ret = ndmpd_dar_tar_v3(session, params, nlp, i+1))
3370                     != 0)
3371                         result = EIO;
3372                 ndmpd_audit_restore(session->ns_connection,
3373                     ep->nm3_opath ? ep->nm3_opath : "NULL",
3374                     session->ns_data.dd_data_addr.addr_type,
3375                     session->ns_tape.td_adapter_name, result);
3376         }
3377 
3378         syslog(LOG_DEBUG, "End of restore list");
3379 
3380         (void) ndmpd_dar_tar_end_v3(session, params, nlp, jname);
3381 
3382         return (ret);
3383 }
3384 
3385 /*
3386  * ndmp_plugin_pre_restore
3387  *
3388  * Wrapper for pre-restore callback with multiple path
3389  */
3390 static int
3391 ndmp_plugin_pre_restore(ndmp_context_t *ctxp, ndmpd_module_params_t *params,
3392     int ncount)
3393 {
3394         mem_ndmp_name_v3_t *ep;
3395         int err;
3396         int i;
3397 
3398         for (i = 0; i < ncount; i++) {


3416  *
3417  * /backup/path/ -> /backup/path
3418  * /backup/path/. -> /backup/path
3419  * /backup/path/../path/ -> /backup/path
3420  * /link-to-backup-path -> /backup/path
3421  *
3422  * Returns:
3423  *      Pointer to the new path (allocated)
3424  *      NULL if the path doesnt exist
3425  */
3426 static char *
3427 get_absolute_path(const char *bkpath)
3428 {
3429         char *pbuf;
3430         char *rv;
3431 
3432         if (!(pbuf = ndmp_malloc(TLM_MAX_PATH_NAME)))
3433                 return (NULL);
3434 
3435         if ((rv = realpath(bkpath, pbuf)) == NULL) {
3436                 syslog(LOG_ERR, "Invalid path [%s] err=%d",
3437                     bkpath, errno);
3438         }
3439         return (rv);
3440 }
3441 
3442 /*
3443  * Expands the format string and logs the resulting message to the
3444  * remote DMA
3445  */
3446 void
3447 ndmp_log_dma(ndmp_context_t *nctx, ndmp_log_dma_type_t lt, const char *fmt, ...)
3448 {
3449         va_list ap;
3450         char buf[256];
3451         ndmpd_module_params_t *params;
3452 
3453         if (nctx == NULL ||
3454             (params = (ndmpd_module_params_t *)nctx->nc_params) == NULL)
3455                 return;
3456 


3464 
3465 /*
3466  * ndmpd_rs_sar_tar_v3
3467  *
3468  * Main non-DAR restore function. It will try to restore all the entries
3469  * that have been backed up.
3470  *
3471  * Parameters:
3472  *   session (input) - pointer to the session
3473  *   params (input) - pointer to the parameters structure
3474  *   nlp (input) - pointer to the nlp structure
3475  *
3476  * Returns:
3477  *   0: on success
3478  *   -1: on error
3479  */
3480 static int
3481 ndmpd_rs_sar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3482     ndmp_lbr_params_t *nlp)
3483 {

3484         char *excl;
3485         char **sels;
3486         int flags;
3487         int err;
3488         tlm_commands_t *cmds;
3489         struct rs_name_maker rn;
3490         ndmp_tar_reader_arg_t arg;
3491         pthread_t rdtp;
3492         int result;
3493         ndmp_context_t nctx;
3494 
3495         result = err = 0;



3496 
3497         if (restore_alloc_structs_v3(session) < 0) {
3498                 return (-1);
3499         }
3500         sels = setupsels(session, params, nlp, 0);
3501         if (!sels) {
3502                 free_structs_v3(session);
3503                 return (-1);
3504         }
3505         excl = NULL;
3506         flags = RSFLG_OVR_ALWAYS;
3507         rn.rn_nlp = nlp;
3508         rn.rn_fp = mknewname;
3509 
3510         nlp->nlp_jstat->js_start_ltime = time(NULL);
3511         nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
3512 
3513         if (!session->ns_data.dd_abort && !session->ns_data.dd_abort) {
3514                 cmds = &nlp->nlp_cmds;
3515                 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
3516                 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
3517                 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
3518 
3519                 syslog(LOG_DEBUG, "Restoring to \"%s\" started.",
3520                     (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3521 
3522                 arg.tr_session = session;
3523                 arg.tr_mod_params = params;
3524                 arg.tr_cmds = cmds;
3525                 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
3526                     (void *)&arg);
3527                 if (err == 0) {
3528                         tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
3529                 } else {
3530                         syslog(LOG_ERR, "Launch ndmp_tar_reader failed");
3531                         free_structs_v3(session);
3532                         return (-1);
3533                 }
3534 
3535                 if (!ndmp_check_utf8magic(cmds->tcs_command)) {
3536                         syslog(LOG_DEBUG, "UTF8Magic not found!");
3537                 } else {
3538                         syslog(LOG_DEBUG, "UTF8Magic found");
3539                 }
3540 
3541                 /* Plug-in module */
3542                 if (ndmp_pl != NULL &&
3543                     ndmp_pl->np_pre_restore != NULL) {
3544                         (void) memset(&nctx, 0, sizeof (ndmp_context_t));
3545                         nctx.nc_cmds = cmds;
3546                         nctx.nc_params = params;
3547                         nctx.nc_ddata = (void *) session;
3548                         if ((err = ndmp_plugin_pre_restore(&nctx, params,
3549                             nlp->nlp_nfiles))
3550                             != 0) {
3551                                 syslog(LOG_ERR, "Pre-restore plug-in: %m");
3552                                 ndmp_stop_local_reader(session, cmds);
3553                                 ndmp_wait_for_reader(cmds);
3554                                 (void) pthread_join(rdtp, NULL);
3555                                 ndmp_stop_remote_reader(session);
3556                                 goto restore_out;
3557                         }
3558                 }
3559 
3560                 cmds->tcs_command->tc_ref++;
3561                 cmds->tcs_writer_count++;
3562 
3563                 if (tm_tar_ops.tm_getdir != NULL) {
3564                         char errbuf[256];
3565 
3566                         err = (tm_tar_ops.tm_getdir)(cmds, cmds->tcs_command,
3567                             nlp->nlp_jstat, &rn, 1, 1, sels, &excl, flags, 0,
3568                             nlp->nlp_mountpoint, session->hardlink_q);
3569                         /*
3570                          * If the fatal error from tm_getdir looks like an
3571                          * errno code, we send the error description to DMA.
3572                          */
3573                         if (err > 0 && strerror_r(err, errbuf,
3574                             sizeof (errbuf)) == 0) {
3575                                 MOD_LOGV3(params, NDMP_LOG_ERROR,
3576                                     "Fatal error during the restore: %s\n",
3577                                     errbuf);
3578                         }
3579                 }
3580 
3581                 cmds->tcs_writer_count--;
3582                 cmds->tcs_command->tc_ref--;
3583                 nlp->nlp_jstat->js_stop_time = time(NULL);
3584 
3585                 /* Send the list of un-recovered files/dirs to the client.  */
3586                 (void) send_unrecovered_list_v3(params, nlp);
3587 
3588                 ndmp_stop_local_reader(session, cmds);
3589                 ndmp_wait_for_reader(cmds);
3590                 (void) pthread_join(rdtp, NULL);
3591 
3592                 ndmp_stop_remote_reader(session);
3593 
3594                 /* exit as if there was an internal error */
3595                 if (session->ns_eof)
3596                         err = -1;
3597                 if (err == -1)
3598                         result = EIO;
3599         }
3600 
3601         (void) send_unrecovered_list_v3(params, nlp); /* nothing restored. */
3602         if (session->ns_data.dd_abort) {
3603                 syslog(LOG_DEBUG, "Restoring to \"%s\" aborted.",
3604                     (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
3605                 result = EINTR;
3606                 ndmpd_audit_restore(session->ns_connection,
3607                     nlp->nlp_restore_path,
3608                     session->ns_data.dd_data_addr.addr_type,
3609                     session->ns_tape.td_adapter_name, result);
3610                 err = -1;
3611         } else {
3612                 syslog(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
3613                     (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL",
3614                     err);
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 
3620 restore_out:
3621                 /* Plug-in module */
3622                 if (ndmp_pl != NULL &&
3623                     ndmp_pl->np_post_restore != NULL &&
3624                     ndmp_pl->np_post_restore(ndmp_pl, &nctx, err) == -1) {
3625                         syslog(LOG_DEBUG, "Post-restore plug-in: %m");
3626                         err = -1;
3627                 }
3628         }
3629 
3630         NDMP_FREE(sels);
3631         free_structs_v3(session);
3632 
3633         return (err);
3634 }
3635 
3636 
3637 /*
3638  * ndmp_backup_get_params_v3
3639  *
3640  * Get the backup parameters from the NDMP env variables
3641  * and log them in the system log and as normal messages
3642  * to the DMA.
3643  *
3644  * Parameters:
3645  *   session (input) - pointer to the session
3646  *   params (input) - pointer to the parameters structure
3647  *
3648  * Returns:
3649  *   NDMP_NO_ERR: on success
3650  *   != NDMP_NO_ERR: otherwise
3651  */
3652 ndmp_error
3653 ndmp_backup_get_params_v3(ndmpd_session_t *session,
3654     ndmpd_module_params_t *params)
3655 {
3656         ndmp_lbr_params_t *nlp;
3657 
3658         if (!session || !params)
3659                 return (NDMP_ILLEGAL_ARGS_ERR);
3660 
3661         nlp = ndmp_get_nlp(session);
3662         if (!nlp) {
3663                 MOD_LOGV3(params, NDMP_LOG_ERROR,
3664                     "Internal error: NULL nlp.\n");
3665                 return (NDMP_ILLEGAL_ARGS_ERR);
3666         } else {
3667                 if (!(nlp->nlp_backup_path = get_backup_path_v3(params)) ||
3668                     !is_valid_backup_dir_v3(params, nlp->nlp_backup_path))
3669                 return (NDMP_ILLEGAL_ARGS_ERR);
3670         }

3671         nlp->nlp_backup_path = get_absolute_path(nlp->nlp_backup_path);
3672         if (!nlp->nlp_backup_path)
3673                 return (NDMP_ILLEGAL_ARGS_ERR);
3674 
3675         /*
3676          * Assume volume is not checkpointed unless found to be below
3677          */


3678         NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
3679 
3680         /*
3681          * Get the zfs volume name from the backup path and store in
3682          * nlp_vol.
3683          */
3684         if (get_zfsvolname(nlp->nlp_vol,
3685             sizeof (nlp->nlp_vol), nlp->nlp_backup_path) == -1) {
3686                 syslog(LOG_ERR,
3687                     "Cannot get volume from [%s] on create",
3688                     nlp->nlp_backup_path);
3689                 NDMP_FREE(nlp->nlp_params);
3690                 return (-1);
3691         }
3692 
3693         /*
3694          * Find out if this data is already checkpointed via. an AutoSync
3695          * or HPR snapshot. If it is, set the flag, and extract the snapshot
3696          * name to use as the nlp_job_name otherwise use the normal
3697          * 'NdmpBackup-nnnn' format.
3698          */
3699         if (fs_is_checkpointed(nlp) &&
3700             (ndmp_autosync_support || ndmp_hpr_support)) {
3701                 NLP_SET(nlp, NLPF_CHKPNTED_PATH);
3702                 syslog(LOG_DEBUG, ">>>> Checkpointed dataset found <<<<");
3703         }
3704 
3705         (void) ndmp_new_job_name(nlp->nlp_job_name,
3706             sizeof (nlp->nlp_job_name));
3707 
3708         syslog(LOG_DEBUG, "New backup job name [%s]",
3709             nlp->nlp_job_name);
3710 
3711         /* Should the st_ctime be ignored when backing up? */
3712         if (ndmp_ignore_ctime) {
3713                 syslog(LOG_DEBUG, "ignoring st_ctime");
3714                 NLP_SET(nlp, NLPF_IGNCTIME);
3715         } else {
3716                 NLP_UNSET(nlp, NLPF_IGNCTIME);
3717         }
3718 
3719         if (ndmp_include_lmtime == TRUE) {
3720                 syslog(LOG_DEBUG, "including st_lmtime");
3721                 NLP_SET(nlp, NLPF_INCLMTIME);
3722         } else {
3723                 NLP_UNSET(nlp, NLPF_INCLMTIME);
3724         }
3725 
3726         syslog(LOG_DEBUG, "flags %x", nlp->nlp_flags);
3727 
3728         get_hist_env_v3(params, nlp);
3729         get_exc_env_v3(params, nlp);
3730         get_inc_env_v3(params, nlp);
3731         get_direct_env_v3(params, nlp);
3732         return (get_backup_level_v3(params, nlp));
3733 }
3734 
3735 
3736 /*
3737  * ndmpd_tar_backup_starter_v3
3738  *
3739  * Create the checkpoint for the backup and do the backup,
3740  * then remove the backup checkpoint if we created it.
3741  * Save the backup time information based on the backup
3742  * type and stop the data server.
3743  *
3744  * Parameters:
3745  *   params (input) - pointer to the parameters structure
3746  *
3747  * Returns:
3748  *   0: on success
3749  *   != 0: otherwise
3750  */
3751 int
3752 ndmpd_tar_backup_starter_v3(void *arg)
3753 {
3754         ndmpd_module_params_t *params = arg;
3755         int err;
3756         ndmpd_session_t *session;
3757         ndmp_lbr_params_t *nlp;



3758 
3759         session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3760         *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3761         ndmp_session_ref(session);

3762 
3763         pthread_cleanup_push(backup_dataset_destroy, nlp);
3764 
3765         err = 0;
3766         if (backup_dataset_create(nlp) < 0) {

3767                 MOD_LOGV3(params, NDMP_LOG_ERROR,
3768                     "Creating checkpoint on \"%s\".\n",
3769                     nlp->nlp_backup_path);
3770                 err = -1;
3771         }
3772 
3773         syslog(LOG_DEBUG, "BACKUP STARTED [%s]", nlp->nlp_snapname);

3774 
3775         if (err == 0) {




3776                 /* Get an estimate of the data size */
3777                 (void) get_backup_size(nlp);


3778 
3779                 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate);
3780                 if (err != 0) {
3781                         syslog(LOG_ERR,
3782                             "Failed to get current backup time %d", err);
3783                 } else {
3784                         log_bk_params_v3(session, params, nlp);
3785                         err = tar_backup_v3(session, params, nlp);
3786                 }
3787         }
3788 
3789         pthread_cleanup_pop(B_TRUE);

3790 



3791         if (err == 0)
3792                 save_backup_date_v3(params, nlp);
3793 
3794         MOD_DONE(params, err);
3795 
3796         /* nlp_params is allocated in start_backup_v3() */
3797         NDMP_FREE(nlp->nlp_params);
3798         NDMP_FREE(nlp->nlp_backup_path);
3799 
3800         NS_DEC(nbk);
3801         ndmp_session_unref(session);
3802         syslog(LOG_DEBUG, "BACKUP COMPLETE [%s] (as jobname %s)",
3803             nlp->nlp_snapname, nlp->nlp_job_name);
3804         return (err);

3805 }
3806 
3807 
3808 /*
3809  * ndmpd_tar_backup_abort_v3
3810  *
3811  * Abort the backup operation and stop the reader thread.
3812  *
3813  * Parameters:
3814  *   module_cookie (input) - pointer to the nlp structure
3815  *
3816  * Returns:
3817  *   0: always
3818  */
3819 int
3820 ndmpd_tar_backup_abort_v3(void *module_cookie)
3821 {
3822         ndmp_lbr_params_t *nlp;
3823 
3824         nlp = (ndmp_lbr_params_t *)module_cookie;


3841  *
3842  * Get the parameters specified for recovery such as restore path, type
3843  * of restore (DAR, non-DAR) etc
3844  *
3845  * Parameters:
3846  *   session (input) - pointer to the session
3847  *   params (input) - pointer to the parameters structure
3848  *
3849  * Returns:
3850  *   NDMP_NO_ERR: on success
3851  *   != NDMP_NO_ERR: otherwise
3852  */
3853 ndmp_error
3854 ndmp_restore_get_params_v3(ndmpd_session_t *session,
3855     ndmpd_module_params_t *params)
3856 {
3857         ndmp_error rv;
3858         ndmp_lbr_params_t *nlp;
3859 
3860         if (!(nlp = ndmp_get_nlp(session))) {
3861                 syslog(LOG_DEBUG, "nlp is NULL");
3862                 rv = NDMP_ILLEGAL_ARGS_ERR;
3863         } else if (!(nlp->nlp_backup_path = get_backup_path_v3(params)))
3864                 rv = NDMP_ILLEGAL_ARGS_ERR;
3865         else if ((nlp->nlp_nfiles = session->ns_data.dd_nlist_len) == 0) {
3866                 syslog(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
3867                 rv = NDMP_ILLEGAL_ARGS_ERR;
3868         } else if (get_rs_path_v3(params, nlp) != NDMP_NO_ERR) {
3869                 rv = NDMP_ILLEGAL_ARGS_ERR;
3870         } else if ((rv = fix_nlist_v3(session, params, nlp)) != NDMP_NO_ERR) {
3871                 syslog(LOG_DEBUG, "fix_nlist_v3: %d", rv);
3872         } else {
3873                 rv = NDMP_NO_ERR;
3874                 get_direct_env_v3(params, nlp);
3875                 if (NLP_ISSET(nlp, NLPF_DIRECT)) {
3876                         if (NLP_ISSET(nlp, NLPF_RECURSIVE)) {
3877                                 /* Currently we dont support DAR on directory */
3878                                 syslog(LOG_DEBUG,
3879                                     "Can't have RECURSIVE and DIRECT together");
3880                                 rv = NDMP_ILLEGAL_ARGS_ERR;
3881                                 return (rv);
3882                         }
3883 
3884                         /*
3885                          * DAR can be done if all the fh_info's are valid.
3886                          */
3887                         if (allvalidfh(session, params)) {
3888                                 ndmp_sort_nlist_v3(session);
3889                         } else {
3890                                 MOD_LOGV3(params, NDMP_LOG_WARNING,
3891                                     "Cannot do direct access recovery. "
3892                                     "Some 'fh_info'es are not valid.\n");
3893                                 NLP_UNSET(nlp, NLPF_DIRECT);
3894                         }
3895                 }
3896 
3897                 log_rs_params_v3(session, params, nlp);
3898         }