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