1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 
   5 /*
   6  * BSD 3 Clause License
   7  *
   8  * Copyright (c) 2007, The Storage Networking Industry Association.
   9  *
  10  * Redistribution and use in source and binary forms, with or without
  11  * modification, are permitted provided that the following conditions
  12  * are met:
  13  *      - Redistributions of source code must retain the above copyright
  14  *        notice, this list of conditions and the following disclaimer.
  15  *
  16  *      - Redistributions in binary form must reproduce the above copyright
  17  *        notice, this list of conditions and the following disclaimer in
  18  *        the documentation and/or other materials provided with the
  19  *        distribution.
  20  *
  21  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  22  *        nor the names of its contributors may be used to endorse or promote
  23  *        products derived from this software without specific prior written
  24  *        permission.
  25  *
  26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36  * POSSIBILITY OF SUCH DAMAGE.
  37  */
  38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
  39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  40 /* 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
  65 
  66 
  67 /* Is Y=yes or T=true */
  68 #define IS_YORT(c)      (strchr("YT", toupper(c)))
  69 
  70 /* Is F=file format (vs D=node-dir format) */
  71 #define IS_F(c)         (toupper(c) == 'F')
  72 
  73 /*
  74  * If path is defined.
  75  */
  76 #define ISDEFINED(cp)   ((cp) && *(cp))
  77 #define SHOULD_LBRBK(bpp)       (!((bpp)->bp_opr & TLM_OP_CHOOSE_ARCHIVE))
  78 
  79 /*
  80  * Component boundary means end of path or on a '/'.  At this
  81  * point both paths should be on component boundary.
  82  */
  83 #define COMPBNDRY(p)    (!*(p) || (*p) == '/')
  84 
  85 typedef struct bk_param_v3 {
  86         ndmpd_session_t *bp_session;
  87         ndmp_lbr_params_t *bp_nlp;
  88         tlm_job_stats_t *bp_js;
  89         tlm_cmd_t *bp_lcmd;
  90         tlm_commands_t *bp_cmds;
  91         tlm_acls_t *bp_tlmacl;
  92         int bp_opr;
  93         char *bp_tmp;
  94         char *bp_chkpnm;
  95         char **bp_excls;
  96         char *bp_unchkpnm;
  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;
 137         char *save;
 138         char **cpp;
 139         int n;
 140 
 141         if (!envp)
 142                 return (NULL);
 143 
 144         while (isspace(*envp))
 145                 envp++;
 146 
 147         if (!*envp)
 148                 return (NULL);
 149 
 150         bp = save = strdup(envp);
 151         if (!bp)
 152                 return (NULL);
 153 
 154         /*
 155          * Since the env variable is not empty, it contains at least one
 156          * component
 157          */
 158         n = 1;
 159         while ((cp = strchr(bp, sep))) {
 160                 if (cp > save && *(cp-1) != '\\')
 161                         n++;
 162 
 163                 bp = cp + 1;
 164         }
 165 
 166         n++; /* for the terminating NULL pointer */
 167         cpp = ndmp_malloc(sizeof (char *) * n);
 168         if (!cpp) {
 169                 free(save);
 170                 return (NULL);
 171         }
 172 
 173         (void) memset(cpp, 0, n * sizeof (char *));
 174         n = 0;
 175         cp = bp = ep = save;
 176         while (*cp)
 177                 if (*cp == sep) {
 178                         *ep = '\0';
 179                         if (strlen(bp) > 0) {
 180                                 cpp[n] = strdup(bp);
 181                                 if (!cpp[n++]) {
 182                                         tlm_release_list(cpp);
 183                                         cpp = NULL;
 184                                         break;
 185                                 }
 186                         }
 187                         ep = bp = ++cp;
 188                 } else if (*cp == '\\') {
 189                         ++cp;
 190                         if (*cp == 'n') {       /* "\n" */
 191                                 *ep++ = '\n';
 192                                 cp++;
 193                         } else if (*cp == 't') {        /* "\t" */
 194                                 *ep++ = '\t';
 195                                 cp++;
 196                         } else
 197                                 *ep++ = *cp++;
 198                 } else
 199                         *ep++ = *cp++;
 200 
 201         *ep = '\0';
 202         if (cpp) {
 203                 if (strlen(bp) > 0) {
 204                         cpp[n] = strdup(bp);
 205                         if (!cpp[n++]) {
 206                                 tlm_release_list(cpp);
 207                                 cpp = NULL;
 208                         } else
 209                                 cpp[n] = NULL;
 210                 }
 211 
 212                 if (n == 0 && cpp != NULL) {
 213                         tlm_release_list(cpp);
 214                         cpp = NULL;
 215                 }
 216         }
 217 
 218         free(save);
 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  */
 309 static boolean_t
 310 inexl(char **lpp, char *ent)
 311 {
 312         if (!lpp || !ent)
 313                 return (FALSE);
 314 
 315         return (inlist(lpp, ent));
 316 }
 317 
 318 
 319 /*
 320  * ininc
 321  *
 322  * Checks if the entry is in the list.  This is used for inclusion
 323  * list.  If the inclusion list is empty, TRUE should be returned
 324  * showing that everything should be included by default.
 325  *
 326  * Parameters:
 327  *   lpp (input) - pointer to the array of strings
 328  *   ent (input) - the entry to be matched
 329  *
 330  * Returns:
 331  *   TRUE: if there is a match or the list is empty
 332  *   FALSE: no match
 333  */
 334 static boolean_t
 335 ininc(char **lpp, char *ent)
 336 {
 337         if (!lpp || !ent || !*ent)
 338                 return (TRUE);
 339 
 340         return (inlist(lpp, ent));
 341 }
 342 
 343 
 344 /*
 345  * setupsels
 346  *
 347  * Set up the selection list for Local B/R functions.  A new array of
 348  * "char *" is created and the pointers point to the original paths of
 349  * the Nlist.
 350  *
 351  * Parameters:
 352  *   session (input) - pointer to the session
 353  *   params (input) - pointer to the parameters structure
 354  *   nlp (input) - pointer to the nlp structure
 355  *   index(input) - If not zero is the DAR entry position
 356  *
 357  * Returns:
 358  *   list pointer: on success
 359  *   NULL: on error
 360  */
 361 /*ARGSUSED*/
 362 char **
 363 setupsels(ndmpd_session_t *session, ndmpd_module_params_t *params,
 364     ndmp_lbr_params_t *nlp, int index)
 365 {
 366         char **lpp, **save;
 367         int i, n;
 368         int len;
 369         int start, end;
 370         mem_ndmp_name_v3_t *ep;
 371 
 372         n = session->ns_data.dd_nlist_len;
 373 
 374         save = lpp = ndmp_malloc(sizeof (char *) * (n + 1));
 375         if (!lpp) {
 376                 MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n");
 377                 return (NULL);
 378         }
 379 
 380         if (index) { /* DAR, just one entry */
 381                 /*
 382                  * We have to setup a list of strings that will not match any
 383                  * file. One DAR entry will be added in the right position later
 384                  * in this function.
 385                  * When the match is called from tar_getdir the
 386                  * location of the selection that matches the entry is
 387                  * important
 388                  */
 389                 for (i = 0; i < n; ++i)
 390                         *(lpp+i) = " ";
 391                 n = 1;
 392                 start = index-1;
 393                 end = start+1;
 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
 435  * as they are the same.  If either of the path or selection are not on
 436  * a component boundary, the match was reported falsefully and no new name
 437  * is generated(Except the situation in which both path and selection
 438  * end with trailing '/' and selection is the prefix of the path).
 439  * Otherwise, the remaining of the path is appended to the
 440  * new name.  The result is saved in the buffer passed.
 441  *
 442  * Parameters:
 443  *   bp (output) - pointer to the result buffer
 444  *   pp (input) - pointer to the path
 445  *   sp (input) - pointer to the selection
 446  *   np (input) - pointer to the new name
 447  *
 448  * Returns:
 449  *   pointer to the bp: on success
 450  *   NULL: otherwise
 451  */
 452 char *
 453 mkrsp(char *bp, char *pp, char *sp, char *np)
 454 {
 455         if (!bp || !pp)
 456                 return (NULL);
 457 
 458 
 459         pp += strspn(pp, "/");
 460         if (sp) {
 461                 sp += strspn(sp, "/");
 462 
 463                 /* skip as much as match */
 464                 while (*sp && *pp && *sp == *pp) {
 465                         sp++;
 466                         pp++;
 467                 }
 468 
 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 
 577         ln = strlen(cp);
 578         cp += ln - 1; /* end of the string */
 579         while (ln > 0 && *cp == '/') {
 580                 *cp-- = '\0';
 581                 ln--;
 582         }
 583 }
 584 
 585 
 586 /*
 587  * joinpath
 588  *
 589  * Join two given paths
 590  */
 591 static char *
 592 joinpath(char *bp, char *pp, char *np)
 593 {
 594         if (pp && *pp) {
 595                 if (np && *np)
 596                         (void) tlm_cat_path(bp, pp, np);
 597                 else
 598                         (void) strlcpy(bp, pp, TLM_MAX_PATH_NAME);
 599         } else {
 600                 if (np && *np)
 601                         (void) strlcpy(bp, np, TLM_MAX_PATH_NAME);
 602                 else
 603                         bp = NULL;
 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
 645  *
 646  * Returns:
 647  *   TRUE: if everything's OK
 648  *   FALSE: otherwise.
 649  */
 650 static boolean_t
 651 is_valid_backup_dir_v3(ndmpd_module_params_t *params, char *bkpath)
 652 {
 653         char *msg;
 654         struct stat64 st;
 655 
 656         if (*bkpath != '/') {
 657                 MOD_LOGV3(params, NDMP_LOG_ERROR,
 658                     "Relative backup path not allowed \"%s\".\n", bkpath);
 659                 return (FALSE);
 660         }
 661         if (stat64(bkpath, &st) < 0) {
 662                 msg = strerror(errno);
 663                 MOD_LOGV3(params, NDMP_LOG_ERROR, "\"%s\" %s.\n",
 664                     bkpath, msg);
 665                 return (FALSE);
 666         }
 667         if (!S_ISDIR(st.st_mode)) {
 668                 /* only directories can be specified as the backup path */
 669                 MOD_LOGV3(params, NDMP_LOG_ERROR,
 670                     "\"%s\" is not a directory.\n", bkpath);
 671                 return (FALSE);
 672         }
 673         if (fs_is_rdonly(bkpath) && !fs_is_chkpntvol(bkpath) &&
 674             fs_is_chkpnt_enabled(bkpath)) {
 675                 /* it is not a chkpnted path */
 676                 MOD_LOGV3(params, NDMP_LOG_ERROR,
 677                     "\"%s\" is not a checkpointed path.\n", bkpath);
 678                 return (FALSE);
 679         }
 680 
 681         return (TRUE);
 682 }
 683 
 684 
 685 /*
 686  * log_date_token_v3
 687  *
 688  * Log the token sequence number and also the date of the
 689  * last backup for token-based backup in the system log
 690  * and also send them as normal log to the client.
 691  *
 692  * Parameters:
 693  *   params (input) - pointer to the parameters structure
 694  *   nlp (input) - pointer to the nlp structure
 695  *
 696  * Returns:
 697  *   void
 698  */
 699 static void
 700 log_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 701 {
 702         MOD_LOGV3(params, NDMP_LOG_NORMAL, "Token sequence counter: %d.\n",
 703             nlp->nlp_tokseq);
 704 
 705         MOD_LOGV3(params, NDMP_LOG_NORMAL, "Date of the last backup: %s.\n",
 706             cctime(&nlp->nlp_tokdate));
 707 
 708         if (nlp->nlp_dmpnm) {
 709                 MOD_LOGV3(params, NDMP_LOG_NORMAL,
 710                     "Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm);
 711         }
 712 }
 713 
 714 
 715 /*
 716  * log_lbr_bk_v3
 717  *
 718  * Log the backup level and data of the backup for LBR-type
 719  * backup in the system log and also send them as normal log
 720  * to the client.
 721  *
 722  * Parameters:
 723  *   params (input) - pointer to the parameters structure
 724  *   nlp (input) - pointer to the nlp structure
 725  *
 726  * Returns:
 727  *   void
 728  */
 729 static void
 730 log_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 731 {
 732         MOD_LOGV3(params, NDMP_LOG_NORMAL,
 733             "Date of this level '%c': %s.\n", nlp->nlp_clevel,
 734             cctime(&nlp->nlp_cdate));
 735 
 736         if (nlp->nlp_dmpnm) {
 737                 MOD_LOGV3(params, NDMP_LOG_NORMAL,
 738                     "Backup date log file name: \"%s\".\n", nlp->nlp_dmpnm);
 739         }
 740 }
 741 
 742 
 743 /*
 744  * log_level_v3
 745  *
 746  * Log the backup level and date of the last and the current
 747  * backup for level-type backup in the system log and also
 748  * send them as normal log to the client.
 749  *
 750  * Parameters:
 751  *   params (input) - pointer to the parameters structure
 752  *   nlp (input) - pointer to the nlp structure
 753  *
 754  * Returns:
 755  *   void
 756  */
 757 static void
 758 log_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 759 {
 760         MOD_LOGV3(params, NDMP_LOG_NORMAL,
 761             "Date of the last level '%u': %s.\n", nlp->nlp_llevel,
 762             cctime(&nlp->nlp_ldate));
 763 
 764         MOD_LOGV3(params, NDMP_LOG_NORMAL,
 765             "Date of this level '%u': %s.\n", nlp->nlp_clevel,
 766             cctime(&nlp->nlp_cdate));
 767 
 768         MOD_LOGV3(params, NDMP_LOG_NORMAL, "Update: %s.\n",
 769             NDMP_TORF(NLP_ISSET(nlp, NLPF_UPDATE)));
 770 }
 771 
 772 
 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         }
 814 }
 815 
 816 
 817 /*
 818  * get_update_env_v3
 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         }
1031 }
1032 
1033 
1034 /*
1035  * get_date_token_v3
1036  *
1037  * Parse the token passed as the argument.  Evaluate it and
1038  * issue any warning or error if needed.  Save the date and
1039  * token sequence in the nlp structure fields.  The sequence
1040  * number in the token should be less than hard-limit.  If
1041  * it's between soft and hard limit, a warning is issued.
1042  * There is a configurable limit which should be less than
1043  * the soft-limit saved in ndmp_max_tok_seq variable.
1044  *
1045  * The NLPF_TOKENBK flag is set in the nlp flags field to
1046  * show that the backup type is token-based.
1047  *
1048  * Parameters:
1049  *   params (input) - pointer to the parameters structure
1050  *   nlp (input) - pointer to the nlp structure
1051  *   basedate (input) - the value of the BASE_DATE environment
1052  *      variable.
1053  *
1054  * Returns:
1055  *   NDMP_NO_ERR: on success
1056  *   != NDMP_NO_ERR: Otherwise
1057  *
1058  */
1059 static ndmp_error
1060 get_date_token_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp,
1061     char *basedate)
1062 {
1063         char *endp;
1064         uint_t seq;
1065         ndmp_error rv;
1066         time_t tstamp;
1067         u_longlong_t tok;
1068 
1069         if (!params || !nlp || !basedate || !*basedate)
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                 /*
1112                  * Issue a warning if the seq is equal to the maximum
1113                  * permitted seq number or equal to the soft-limit.
1114                  */
1115                 if (seq == NDMP_TOKSEQ_SLIMIT) {
1116                         MOD_LOGV3(params, NDMP_LOG_WARNING,
1117                             "The sequence counter of the token has reached "
1118                             "the soft-limit.\n");
1119                         MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1120                             "Token sequence: %u, soft-limit: %u.\n",
1121                             seq, NDMP_TOKSEQ_SLIMIT);
1122                 } else if ((int)seq == ndmp_get_max_tok_seq()) {
1123                         MOD_LOGV3(params, NDMP_LOG_WARNING,
1124                             "The sequence counter of the token has reached "
1125                             "the maximum permitted value.\n");
1126                         MOD_LOGCONTV3(params, NDMP_LOG_WARNING,
1127                             "Token sequence: %u, maxiumum value: %u.\n",
1128                             seq, ndmp_get_max_tok_seq());
1129                 }
1130 
1131                 /*
1132                  * The current seq is equal to the seq field of the
1133                  * token.  It will be increased after successful backup
1134                  * before setting the DUMP_DATE environment variable.
1135                  */
1136                 nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME");
1137                 NLP_SET(nlp, NLPF_TOKENBK);
1138                 NLP_UNSET(nlp, NLPF_LEVELBK);
1139                 NLP_UNSET(nlp, NLPF_LBRBK);
1140                 nlp->nlp_tokseq = seq;
1141                 nlp->nlp_tokdate = tstamp;
1142                 /*
1143                  * The value of nlp_cdate will be set to the checkpoint
1144                  * creation time after it is created.
1145                  */
1146         }
1147 
1148         return (rv);
1149 }
1150 
1151 
1152 /*
1153  * get_lbr_bk_v3
1154  *
1155  * Sets the level fields of the nlp structures for
1156  * LBR-type backup.  The NLPF_LBRBK flag of the
1157  * nlp flags is also set to show the backup type.
1158  *
1159  * Parameters:
1160  *   params (input) - pointer to the parameters structure
1161  *   nlp (input) - pointer to the nlp structure
1162  *   type (input) - the backup level: 'F', 'A', 'I', 'D' or
1163  *      their lower-case values.
1164  *
1165  * Returns:
1166  *   NDMP_NO_ERR: on success
1167  *   != NDMP_NO_ERR: Otherwise
1168  */
1169 static ndmp_error
1170 get_lbr_bk_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp, char *type)
1171 {
1172         if (!params || !nlp || !type || !*type)
1173                 return (NDMP_ILLEGAL_ARGS_ERR);
1174 
1175         NLP_SET(nlp, NLPF_LBRBK);
1176         NLP_UNSET(nlp, NLPF_TOKENBK);
1177         NLP_UNSET(nlp, NLPF_LEVELBK);
1178         nlp->nlp_dmpnm = MOD_GETENV(params, "DMP_NAME");
1179         nlp->nlp_llevel = toupper(*type);
1180         nlp->nlp_ldate = (time_t)0;
1181         nlp->nlp_clevel = nlp->nlp_llevel;
1182         (void) time(&nlp->nlp_cdate);
1183 
1184         return (NDMP_NO_ERR);
1185 }
1186 
1187 
1188 /*
1189  * get_backup_level_v3
1190  *
1191  * Gets the backup level from the environment variables.  If
1192  * BASE_DATE is specified, it will be used, otherwise LEVEL
1193  * will be used.  If neither is specified, LEVEL = '0' is
1194  * assumed.
1195  *
1196  * Parameters:
1197  *   params (input) - pointer to the parameters structure
1198  *   nlp (input) - pointer to the nlp structure
1199  *
1200  * Returns:
1201  *   NDMP_NO_ERR: on success
1202  *   != NDMP_NO_ERR: Otherwise
1203  */
1204 static ndmp_error
1205 get_backup_level_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1206 {
1207         char *envp;
1208         ndmp_error rv;
1209 
1210         /*
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))
1252                 return (get_lbr_bk_v3(params, nlp, envp));
1253 
1254         if (!isdigit(*envp)) {
1255                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1256                     "Invalid backup level \"%s\".\n", envp);
1257                 return (NDMP_ILLEGAL_ARGS_ERR);
1258         }
1259 
1260         NLP_SET(nlp, NLPF_LEVELBK);
1261         NLP_UNSET(nlp, NLPF_LBRBK);
1262         NLP_UNSET(nlp, NLPF_TOKENBK);
1263         nlp->nlp_llevel = *envp - '0';
1264         nlp->nlp_ldate = 0;
1265         nlp->nlp_clevel = nlp->nlp_llevel;
1266         /*
1267          * The value of nlp_cdate will be set to the checkpoint
1268          * creation time after it is created.
1269          */
1270         if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
1271             &nlp->nlp_ldate) < 0) {
1272                 MOD_LOGV3(params, NDMP_LOG_ERROR,
1273                     "Getting dumpdates for %s level '%c'.\n",
1274                     nlp->nlp_backup_path, *envp);
1275                 return (NDMP_NO_MEM_ERR);
1276         } else {
1277                 get_update_env_v3(params, nlp);
1278                 rv = NDMP_NO_ERR;
1279         }
1280 
1281         return (rv);
1282 }
1283 
1284 
1285 /*
1286  * save_date_token_v3
1287  *
1288  * Make the value of DUMP_DATE env variable and append the values
1289  * of the current backup in the file specified with the DMP_NAME
1290  * env variable if any file is specified.  The file will be
1291  * relative name in the backup directory path.
1292  *
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  */
1400 static void
1401 save_backup_date_v3(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
1402 {
1403         if (!params || !nlp)
1404                 return;
1405 
1406         if (NLP_ISSET(nlp, NLPF_TOKENBK))
1407                 save_date_token_v3(params, nlp);
1408         else if (NLP_ISSET(nlp, NLPF_LBRBK))
1409                 save_lbr_bk_v3(params, nlp);
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",
1687                     bpp->bp_unchkpnm, p);
1688 
1689         if (tm_tar_ops.tm_putdir != NULL)
1690                 (void) (tm_tar_ops.tm_putdir)(fullpath, bpp->bp_tlmacl,
1691                     bpp->bp_lcmd, bpp->bp_js);
1692 
1693         apos = tlm_get_data_offset(bpp->bp_lcmd);
1694         bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed +=
1695             apos - bpos;
1696 
1697         return (0);
1698 }
1699 
1700 
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 == '/')
1762                 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s%s",
1763                     bpp->bp_unchkpnm, p);
1764         else
1765                 (void) snprintf(fullpath, TLM_MAX_PATH_NAME, "%s/%s",
1766                     bpp->bp_unchkpnm, p);
1767 
1768         if (tm_tar_ops.tm_putfile != NULL)
1769                 rv = (tm_tar_ops.tm_putfile)(fullpath, ent, pnp->tn_path,
1770                     bpp->bp_tlmacl, bpp->bp_cmds, bpp->bp_lcmd, bpp->bp_js,
1771                     bpp->bp_session->hardlink_q);
1772 
1773         apos = tlm_get_data_offset(bpp->bp_lcmd);
1774         bpp->bp_session->ns_data.dd_module.dm_stats.ms_bytes_processed +=
1775             apos - bpos;
1776 
1777         return (rv < 0 ? rv : 0);
1778 }
1779 
1780 
1781 /*
1782  * check_bk_args
1783  *
1784  * Check the argument of the bpp.  This is shared function between
1785  * timebk_v3 and lbrbk_v3 functions.  The checks include:
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
2030  * the backup path. This is used to get an estimate
2031  * of the progress of backup during NDMP backup
2032  */
2033 static int
2034 size_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
2035 {
2036         struct stat64 *stp;
2037 
2038         stp = enp->tn_path ? enp->tn_st : pnp->tn_st;
2039         *((u_longlong_t *)arg) += stp->st_size;
2040 
2041         return (0);
2042 }
2043 
2044 /*
2045  * timebk_v3
2046  *
2047  * The callback function for backing up objects based on
2048  * their time stamp.  This is shared between token-based
2049  * and level-based backup, which look at the time stamps
2050  * of the objects to determine if they should be backed
2051  * up.
2052  *
2053  * Parameters:
2054  *   arg (input) - pointer to the backup parameters structure
2055  *   pnp (input) - pointer to the path node
2056  *   enp (input) - pointer to the entry node
2057  *
2058  * Returns:
2059  *   0: if backup should continue
2060  *   -1: if the backup should be stopped
2061  *   FST_SKIP: if backing up the current directory is enough
2062  */
2063 static int
2064 timebk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp)
2065 {
2066         char *ent;
2067         int rv;
2068         time_t t;
2069         bk_param_v3_t *bpp;
2070         struct stat64 *stp;
2071         fs_fhandle_t *fhp;
2072 
2073         bpp = (bk_param_v3_t *)arg;
2074 
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));
2124                         bpp->bp_tlmacl->acl_fil_fh = *fhp;
2125                         (void) backup_filev3(bpp, pnp, enp);
2126                 }
2127         }
2128 
2129         return (rv);
2130 }
2131 
2132 
2133 /*
2134  * lbrbk_v3
2135  *
2136  * The callback function for backing up objects based on
2137  * their archive directory bit.  This is used in LBR-type
2138  * backup.  In which the objects are backed up if their
2139  * archive bit is set.
2140  *
2141  * Parameters:
2142  *   arg (input) - pointer to the backup parameters structure
2143  *   pnp (input) - pointer to the path node
2144  *   enp (input) - pointer to the entry node
2145  *
2146  * Returns:
2147  *   0: if backup should continue
2148  *   -1: if the backup should be stopped
2149  *   FST_SKIP: if backing up the current directory is enough
2150  */
2151 static int
2152 lbrbk_v3(void *arg, fst_node_t *pnp, fst_node_t *enp)
2153 {
2154         char *ent;
2155         int rv;
2156         bk_param_v3_t *bpp;
2157         struct stat64 *stp;
2158         fs_fhandle_t *fhp;
2159 
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
2621  *
2622  * Check if the recovery list is valid and fix it if there are some
2623  * unspecified entries in it. It checks for original, destination
2624  * and new path for all NDMP names provided inside the list.
2625  *
2626  * V3: dpath is the destination directory.  If newnm is not NULL, the
2627  * destination path is dpath/newnm.  Otherwise the destination path is
2628  * dpath/opath_last_node, where opath_last_node is the last node in opath.
2629  *
2630  * V4: If newnm is not NULL, dpath is the destination directory, and
2631  * dpath/newnm is the destination path.  If newnm is NULL, dpath is
2632  * the destination path (opath is not involved in forming destination path).
2633  */
2634 ndmp_error
2635 fix_nlist_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2636     ndmp_lbr_params_t *nlp)
2637 {
2638         char *cp, *buf, *bp;
2639         int i, n;
2640         int iswrbk;
2641         int bvexists;
2642         ndmp_error rv;
2643         mem_ndmp_name_v3_t *ep;
2644         char *dp;
2645         char *nm;
2646         int existsvol;
2647         int isrwdst;
2648 
2649         buf = ndmp_malloc(TLM_MAX_PATH_NAME);
2650         if (!buf) {
2651                 MOD_LOGV3(params, NDMP_LOG_ERROR, "Insufficient memory.\n");
2652                 return (NDMP_NO_MEM_ERR);
2653         }
2654 
2655         bvexists = fs_volexist(nlp->nlp_backup_path);
2656         iswrbk = voliswr(nlp->nlp_backup_path);
2657 
2658         rv = NDMP_NO_ERR;
2659         n = session->ns_data.dd_nlist_len;
2660         for (i = 0; i < n; i++) {
2661                 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2662                 if (!ep)
2663                         continue;
2664 
2665                 /* chop off the trailing slashes */
2666                 chopslash(ep->nm3_opath);
2667 
2668                 chopslash(ep->nm3_dpath);
2669                 chopslash(ep->nm3_newnm);
2670 
2671                 /* existing and non-empty destination path */
2672                 if (ISDEFINED(ep->nm3_dpath)) {
2673                         dp = ep->nm3_dpath;
2674                         existsvol = fs_volexist(dp);
2675                         isrwdst = voliswr(dp);
2676                 } else {
2677                         /* the default destination path is backup directory */
2678                         dp = nlp->nlp_backup_path;
2679                         existsvol = bvexists;
2680                         isrwdst = iswrbk;
2681                 }
2682 
2683                 /* check the destination directory exists and is writable */
2684                 if (!existsvol) {
2685                         rv = NDMP_ILLEGAL_ARGS_ERR;
2686                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2687                             "Invalid destination path volume "
2688                             "\"%s\".\n", dp);
2689                         break;
2690                 }
2691                 if (!isrwdst) {
2692                         rv = NDMP_ILLEGAL_ARGS_ERR;
2693                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2694                             "The destination path volume is not "
2695                             "writable \"%s\".\n", dp);
2696                         break;
2697                 }
2698 
2699                 /*
2700                  * If new name is not specified, the default new name is
2701                  * the last component of the original path, if any
2702                  * (except in V4).
2703                  */
2704                 if (ISDEFINED(ep->nm3_newnm)) {
2705                         nm = ep->nm3_newnm;
2706                 } else {
2707                         char *p, *q;
2708 
2709                         /*
2710                          * Find the last component of nm3_opath.
2711                          * nm3_opath has no trailing '/'.
2712                          */
2713                         p = strrchr(ep->nm3_opath, '/');
2714                         nm = p ? p + 1 : ep->nm3_opath;
2715 
2716                         /*
2717                          * In DDAR the last component could
2718                          * be repeated in nm3_dpath
2719                          */
2720                         q = strrchr(ep->nm3_dpath, '/');
2721                         q = q ? q + 1 : ep->nm3_dpath;
2722                         if (strcmp(nm, q) == 0)
2723                                 nm = NULL;
2724 
2725                 }
2726 
2727                 bp = joinpath(buf, dp, nm);
2728                 if (!bp) {
2729                         /*
2730                          * Note: What should be done with this entry?
2731                          * We leave it untouched for now, hence no path in
2732                          * the backup image matches with this entry and will
2733                          * be reported as not found.
2734                          */
2735                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2736                             "Destination path too long(%s/%s)", dp, nm);
2737                         continue;
2738                 }
2739                 cp = strdup(bp);
2740                 if (!cp) {
2741                         MOD_LOGV3(params, NDMP_LOG_ERROR,
2742                             "Insufficient memory.\n");
2743                         rv = NDMP_NO_MEM_ERR;
2744                         break;
2745                 }
2746                 free(ep->nm3_dpath);
2747                 ep->nm3_dpath = cp;
2748                 NDMP_FREE(ep->nm3_newnm);
2749 
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;
2796         boolean_t rv;
2797         mem_ndmp_name_v3_t *ep;
2798 
2799         rv = TRUE;
2800         n = session->ns_data.dd_nlist_len;
2801         for (i = 0; i < n; i++) {
2802                 ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i);
2803                 if (!ep)
2804                         continue;
2805                 /*
2806                  * The fh_info's sent from the client are multiples
2807                  * of RECORDSIZE which is 512 bytes.
2808                  *
2809                  * All our fh_info's are at the RECORDSIZE boundary.  If there
2810                  * is any fh_info that is less than RECORDSIZE (this covers 0
2811                  * and -1 values too), then the result is that DAR cannot be
2812                  * done.
2813                  */
2814                 if (ep->nm3_fh_info < RECORDSIZE ||
2815                     ep->nm3_fh_info % RECORDSIZE != 0) {
2816                         rv = FALSE;
2817                         break;
2818                 }
2819         }
2820 
2821         return (rv);
2822 }
2823 
2824 
2825 /*
2826  * log_rs_params_v3
2827  *
2828  * Log a copy of all values of the restore parameters
2829  */
2830 void
2831 log_rs_params_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
2832     ndmp_lbr_params_t *nlp)
2833 {
2834         MOD_LOGV3(params, NDMP_LOG_NORMAL, "Restoring to \"%s\".\n",
2835             (nlp->nlp_restore_path) ? nlp->nlp_restore_path : "NULL");
2836 
2837         if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_LOCAL) {
2838                 MOD_LOGV3(params, NDMP_LOG_NORMAL, "Tape server: local.\n");
2839                 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2840                     "Tape record size: %d.\n",
2841                     session->ns_mover.md_record_size);
2842         } else if (session->ns_data.dd_data_addr.addr_type == NDMP_ADDR_TCP)
2843                 MOD_LOGV3(params, NDMP_LOG_NORMAL,
2844                     "Tape server: remote at %s:%d.\n",
2845                     inet_ntoa(IN_ADDR(session->ns_data.dd_data_addr.tcp_ip_v3)),
2846                     session->ns_data.dd_data_addr.tcp_port_v3);
2847         else
2848                 MOD_LOGV3(params, NDMP_LOG_ERROR,
2849                     "Unknown tape server address type.\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
3332  * it restores the file.
3333  * When all restore requests are done it calls the deconstructor to clean
3334  * everything up.
3335  *
3336  * Parameters:
3337  *   session (input) - pointer to the session
3338  *   params (input) - pointer to the parameters structure
3339  *   nlp (input) - pointer to the nlp structure
3340  *
3341  * Returns:
3342  *   0: on success
3343  *   -1: on error
3344  */
3345 static int
3346 ndmpd_rs_dar_tar_v3(ndmpd_session_t *session, ndmpd_module_params_t *params,
3347     ndmp_lbr_params_t *nlp)
3348 {
3349         mem_ndmp_name_v3_t *ep;
3350         u_longlong_t len;
3351         char *jname;
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++) {
3424                 if (!(ep = (mem_ndmp_name_v3_t *)MOD_GETNAME(params, i)))
3425                         continue;
3426                 if ((err = ndmp_pl->np_pre_restore(ndmp_pl, ctxp,
3427                     ep->nm3_opath, ep->nm3_dpath)) != 0)
3428                         return (err);
3429         }
3430 
3431         return (0);
3432 }
3433 
3434 /*
3435  * get_absolute_path
3436  *
3437  * Get resolved path name which does not involve ".", ".." or extra
3438  * "/" or symbolic links.
3439  *
3440  * e.g.
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 
3482         va_start(ap, fmt);
3483         (void) vsnprintf(buf, sizeof (buf), fmt, ap);
3484         va_end(ap);
3485 
3486         MOD_LOGV3(params, (ndmp_log_type)lt, "%s", buf);
3487 }
3488 
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;
3835         if (nlp && nlp->nlp_session) {
3836                 if (nlp->nlp_session->ns_data.dd_data_addr.addr_type ==
3837                     NDMP_ADDR_TCP &&
3838                     nlp->nlp_session->ns_data.dd_sock != -1) {
3839                         (void) close(nlp->nlp_session->ns_data.dd_sock);
3840                         nlp->nlp_session->ns_data.dd_sock = -1;
3841                 }
3842                 ndmp_stop_reader_thread(nlp->nlp_session);
3843         }
3844 
3845         return (0);
3846 }
3847 
3848 
3849 /*
3850  * ndmp_restore_get_params_v3
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         }
3909 
3910         return (rv);
3911 }
3912 
3913 
3914 /*
3915  * ndmpd_tar_restore_starter_v3
3916  *
3917  * The main restore starter function. It will start a DAR or
3918  * non-DAR recovery based on the parameters. (V3 and V4 only)
3919  *
3920  * Parameters:
3921  *   params (input) - pointer to the parameters structure
3922  *
3923  * Returns:
3924  *   NDMP_NO_ERR: on success
3925  *   != NDMP_NO_ERR: otherwise
3926  */
3927 int
3928 ndmpd_tar_restore_starter_v3(void *arg)
3929 {
3930         ndmpd_module_params_t *params = arg;
3931         int err;
3932         ndmpd_session_t *session;
3933         ndmp_lbr_params_t *nlp;
3934 
3935 
3936         session = (ndmpd_session_t *)(params->mp_daemon_cookie);
3937         *(params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
3938         ndmp_session_ref(session);
3939 
3940         if (NLP_ISSET(nlp, NLPF_DIRECT))
3941                 err = ndmpd_rs_dar_tar_v3(session, params, nlp);
3942         else
3943                 err = ndmpd_rs_sar_tar_v3(session, params, nlp);
3944 
3945         MOD_DONE(params, err);
3946 
3947         NS_DEC(nrs);
3948         /* nlp_params is allocated in start_recover() */
3949         NDMP_FREE(nlp->nlp_params);
3950         ndmp_session_unref(session);
3951         return (err);
3952 
3953 }
3954 
3955 /*
3956  * ndmp_tar_restore_abort_v3
3957  *
3958  * Restore abort function (V3 and V4 only)
3959  *
3960  * Parameters:
3961  *   module_cookie (input) - pointer to nlp
3962  *
3963  * Returns:
3964  *   0
3965  */
3966 int
3967 ndmpd_tar_restore_abort_v3(void *module_cookie)
3968 {
3969         ndmp_lbr_params_t *nlp;
3970 
3971         nlp = (ndmp_lbr_params_t *)module_cookie;
3972         if (nlp != NULL && nlp->nlp_session != NULL) {
3973                 if (nlp->nlp_session->ns_data.dd_mover.addr_type ==
3974                     NDMP_ADDR_TCP &&
3975                     nlp->nlp_session->ns_data.dd_sock != -1) {
3976                         (void) close(nlp->nlp_session->ns_data.dd_sock);
3977                         nlp->nlp_session->ns_data.dd_sock = -1;
3978                 }
3979                 ndmp_stop_writer_thread(nlp->nlp_session);
3980         }
3981 
3982         return (0);
3983 }