Print this page
NEX-13374 NDMP should be able to backup unmounted ZFS filesystems
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9532 NDMP: readdir errors when file/directory has special characters
Reviewed by: Peer Dampmann <peer.dampmann@nexenta.com>
Reviewed by: Alexander Eremin <alexander.eremin@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Revert "NEX-5801 Snapshots left over after failed backups"
This reverts commit f182fb95f09036db71fbfc6f0a6b90469b761f21.
NEX-5801 Snapshots left over after failed backups
Reviewed by: Rick Mesta <rick.mesta@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
NEX-2990 ndmpd dumping core when used with ndmpcopy
NEX-2911 NDMP logging should use syslog and is too chatty
NEX-559 NDMP cannot backup/restore a file which spans multiple tapes
   1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.

   3  */
   4 
   5 /*
   6  * BSD 3 Clause License
   7  *
   8  * Copyright (c) 2007, The Storage Networking Industry Association.
   9  *
  10  * Redistribution and use in source and binary forms, with or without
  11  * modification, are permitted provided that the following conditions
  12  * are met:
  13  *      - Redistributions of source code must retain the above copyright
  14  *        notice, this list of conditions and the following disclaimer.
  15  *
  16  *      - Redistributions in binary form must reproduce the above copyright
  17  *        notice, this list of conditions and the following disclaimer in
  18  *        the documentation and/or other materials provided with the
  19  *        distribution.
  20  *
  21  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  22  *        nor the names of its contributors may be used to endorse or promote
  23  *        products derived from this software without specific prior written
  24  *        permission.
  25  *
  26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  36  * POSSIBILITY OF SUCH DAMAGE.
  37  */
  38 /* Copyright (c) 2007, The Storage Networking Industry Association. */
  39 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  40 /* Copyright 2014 Nexenta Systems, Inc. All rights reserved. */
  41 
  42 #include <sys/stat.h>
  43 #include <sys/types.h>
  44 #include <sys/socket.h>

  45 #include <errno.h>
  46 #include <stdio.h>
  47 #include <string.h>
  48 #include <unistd.h>
  49 #include <time.h>
  50 #include <cstack.h>
  51 #include <dirent.h>
  52 #include <traverse.h>
  53 #include "bitmap.h"
  54 #include "ndmpd.h"
  55 #include "tlm_buffers.h"
  56 
  57 
  58 typedef struct ndmp_run_args {
  59         char *nr_chkp_nm;
  60         char *nr_unchkp_nm;
  61         char **nr_excls;
  62 } ndmp_run_args_t;
  63 
  64 


  67  *
  68  * Allocate the structures before performing backup
  69  *
  70  * Parameters:
  71  *   sesison (input) - session handle
  72  *   jname (input) - backup job name
  73  *
  74  * Returns:
  75  *   0: on success
  76  *  -1: otherwise
  77  */
  78 static int
  79 backup_create_structs(ndmpd_session_t *session, char *jname)
  80 {
  81         int n;
  82         long xfer_size;
  83         ndmp_lbr_params_t *nlp;
  84         tlm_commands_t *cmds;
  85 
  86         if ((nlp = ndmp_get_nlp(session)) == NULL) {
  87                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
  88                 return (-1);
  89         }
  90 
  91         if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) {
  92                 NDMP_LOG(LOG_DEBUG, "Creating job stats");
  93                 return (-1);
  94         }
  95 
  96         cmds = &nlp->nlp_cmds;
  97         (void) memset(cmds, 0, sizeof (*cmds));
  98 
  99         xfer_size = ndmp_buffer_get_size(session);
 100         if (xfer_size < 512*KILOBYTE) {
 101                 /*
 102                  * Read multiple of mover_record_size near to 512K.  This
 103                  * will prevent the data being copied in the mover buffer
 104                  * when we write the data.
 105                  */
 106                 if ((n = (512 * KILOBYTE/xfer_size)) <= 0)
 107                         n = 1;
 108                 xfer_size *= n;
 109                 NDMP_LOG(LOG_DEBUG, "Adjusted read size: %d", xfer_size);
 110         }
 111 
 112         cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
 113         if (cmds->tcs_command == NULL) {
 114                 NDMP_LOG(LOG_DEBUG, "Error creating ipc buffers");
 115                 tlm_un_ref_job_stats(jname);
 116                 return (-1);
 117         }
 118 
 119         nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
 120             ndmpd_file_history_path,
 121             ndmpd_file_history_dir,
 122             ndmpd_file_history_node);
 123         if (nlp->nlp_logcallbacks == NULL) {
 124                 tlm_release_reader_writer_ipc(cmds->tcs_command);
 125                 tlm_un_ref_job_stats(jname);
 126                 return (-1);
 127         }
 128         nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
 129 
 130         return (0);
 131 }
 132 
 133 
 134 /*


 136  *
 137  * Allocate structures for performing a restore
 138  *
 139  * Parameters:
 140  *   sesison (input) - session handle
 141  *   jname (input) - backup job name
 142  *
 143  * Returns:
 144  *   0: on success
 145  *  -1: otherwise
 146  */
 147 static int
 148 restore_create_structs(ndmpd_session_t *session, char *jname)
 149 {
 150         int i;
 151         long xfer_size;
 152         ndmp_lbr_params_t *nlp;
 153         tlm_commands_t *cmds;
 154 
 155         if ((nlp = ndmp_get_nlp(session)) == NULL) {
 156                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
 157                 return (-1);
 158         }
 159         if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) {
 160                 NDMP_LOG(LOG_DEBUG, "Creating job stats");
 161                 return (-1);
 162         }
 163 
 164         cmds = &nlp->nlp_cmds;
 165         (void) memset(cmds, 0, sizeof (*cmds));
 166 
 167         xfer_size = ndmp_buffer_get_size(session);
 168         cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
 169         if (cmds->tcs_command == NULL) {
 170                 NDMP_LOG(LOG_DEBUG, "Error creating ipc buffers");
 171                 tlm_un_ref_job_stats(jname);
 172                 return (-1);
 173         }
 174 
 175         nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
 176             ndmpd_path_restored, NULL, NULL);
 177         if (nlp->nlp_logcallbacks == NULL) {
 178                 tlm_release_reader_writer_ipc(cmds->tcs_command);
 179                 tlm_un_ref_job_stats(jname);
 180                 return (-1);
 181         }
 182         nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
 183 
 184         nlp->nlp_restored = ndmp_malloc(sizeof (boolean_t) * nlp->nlp_nfiles);
 185         if (nlp->nlp_restored == NULL) {
 186                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
 187                 tlm_release_reader_writer_ipc(cmds->tcs_command);
 188                 tlm_un_ref_job_stats(jname);
 189                 return (-1);
 190         }


 198 /*
 199  * send_unrecovered_list
 200  *
 201  * Creates a list of restored files
 202  *
 203  * Parameters:
 204  *   params (input) - NDMP parameters
 205  *   nlp (input) - NDMP/LBR parameters
 206  *
 207  * Returns:
 208  *   0: on success
 209  *  -1: otherwise
 210  */
 211 static int
 212 send_unrecovered_list(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 213 {
 214         int i, rv;
 215         ndmp_name *ent;
 216 
 217         if (params == NULL) {
 218                 NDMP_LOG(LOG_DEBUG, "params == NULL");
 219                 return (-1);
 220         }
 221         if (nlp == NULL) {
 222                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
 223                 return (-1);
 224         }
 225 
 226         rv = 0;
 227         for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
 228                 NDMP_LOG(LOG_DEBUG, "nlp->nlp_restored[%d]: %s", i,
 229                     nlp->nlp_restored[i] ? "TRUE" : "FALSE");
 230 
 231                 if (!nlp->nlp_restored[i]) {
 232                         ent = (ndmp_name *)MOD_GETNAME(params, i);
 233                         if (ent == NULL) {
 234                                 NDMP_LOG(LOG_DEBUG, "ent == NULL");
 235                                 rv = -1;
 236                                 break;
 237                         }
 238                         if (ent->name == NULL) {
 239                                 NDMP_LOG(LOG_DEBUG, "ent->name == NULL");
 240                                 rv = -1;
 241                                 break;
 242                         }
 243 
 244                         NDMP_LOG(LOG_DEBUG, "ent.name: \"%s\"", ent->name);
 245 
 246                         rv = MOD_FILERECOVERD(params, ent->name, ENOENT);
 247                         if (rv < 0)
 248                                 break;
 249                 }
 250         }
 251 
 252         return (rv);
 253 }
 254 
 255 
 256 /*
 257  * backup_release_structs
 258  *
 259  * Deallocated the NDMP/LBR specific parameters
 260  *
 261  * Parameters:
 262  *   session (input) - session handle
 263  *
 264  * Returns:
 265  *   void
 266  */
 267 /*ARGSUSED*/
 268 static void
 269 backup_release_structs(ndmpd_session_t *session)
 270 {
 271         ndmp_lbr_params_t *nlp;
 272         tlm_commands_t *cmds;
 273 
 274         if ((nlp = ndmp_get_nlp(session)) == NULL) {
 275                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
 276                 return;
 277         }
 278         cmds = &nlp->nlp_cmds;
 279         if (cmds == NULL) {
 280                 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
 281                 return;
 282         }
 283 
 284         if (nlp->nlp_logcallbacks != NULL) {
 285                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
 286                 nlp->nlp_logcallbacks = NULL;
 287         } else {
 288                 NDMP_LOG(LOG_DEBUG, "FH CALLBACKS == NULL");
 289         }
 290 
 291         if (cmds->tcs_command != NULL) {
 292                 if (cmds->tcs_command->tc_buffers != NULL)
 293                         tlm_release_reader_writer_ipc(cmds->tcs_command);
 294                 else
 295                         NDMP_LOG(LOG_DEBUG, "BUFFERS == NULL");
 296                 cmds->tcs_command = NULL;
 297         } else {
 298                 NDMP_LOG(LOG_DEBUG, "COMMAND == NULL");
 299         }
 300 
 301         if (nlp->nlp_bkmap >= 0) {
 302                 (void) dbm_free(nlp->nlp_bkmap);
 303                 nlp->nlp_bkmap = -1;
 304         }
 305 
 306         if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER &&
 307             nlp->nlp_restored != NULL) {
 308                 free(nlp->nlp_restored);
 309                 nlp->nlp_restored = NULL;
 310         } else {
 311                 NDMP_LOG(LOG_DEBUG, "nlp_restored == NULL");
 312         }
 313 }
 314 
 315 /*
 316  * ndmp_write_utf8magic
 317  *
 318  * Write a magic pattern to the tar header. This is used
 319  * as a crest to indicate that tape belongs to us.
 320  */
 321 int
 322 ndmp_write_utf8magic(tlm_cmd_t *cmd)
 323 {
 324         char *cp;
 325         long actual_size;
 326 
 327         if (cmd->tc_buffers == NULL) {
 328                 NDMP_LOG(LOG_DEBUG, "cmd->tc_buffers == NULL");
 329                 return (-1);
 330         }
 331 
 332         cp = tlm_get_write_buffer(RECORDSIZE, &actual_size,
 333             cmd->tc_buffers, TRUE);
 334         if (actual_size < RECORDSIZE) {
 335                 NDMP_LOG(LOG_DEBUG, "Couldn't get enough buffer");
 336                 return (-1);
 337         }
 338 
 339         (void) strlcpy(cp, NDMPUTF8MAGIC, RECORDSIZE);
 340         return (0);
 341 }
 342 
 343 
 344 /*
 345  * timecmp
 346  *
 347  * This callback function is used during backup.  It checks
 348  * if the object specified by the 'attr' should be backed
 349  * up or not.
 350  *
 351  * Directories are backed up anyways for dump format.
 352  * If this function is called, then the directory is
 353  * marked in the bitmap vector, it shows that either the
 354  * directory itself is modified or there is something below
 355  * it that will be backed up.


 360  * By setting ndmp_force_bk_dirs global variable to a non-zero
 361  * value, directories are backed up anyways.
 362  *
 363  * Backing up the directories unconditionally, helps
 364  * restoring the metadata of directories as well, when one
 365  * of the objects below them are being restored.
 366  *
 367  * For non-directory objects, if the modification or change
 368  * time of the object is after the date specified by the
 369  * bk_selector_t, the the object must be backed up.
 370  *
 371  */
 372 static boolean_t
 373 timecmp(bk_selector_t *bksp,
 374                 struct stat64 *attr)
 375 {
 376         ndmp_lbr_params_t *nlp;
 377 
 378         nlp = (ndmp_lbr_params_t *)bksp->bs_cookie;
 379         if (S_ISDIR(attr->st_mode) && ndmp_force_bk_dirs) {
 380                 NDMP_LOG(LOG_DEBUG, "d(%lu)",
 381                     (uint_t)attr->st_ino);
 382                 return (TRUE);
 383         }
 384         if (S_ISDIR(attr->st_mode) &&
 385             dbm_getone(nlp->nlp_bkmap, (u_longlong_t)attr->st_ino) &&
 386             ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
 387             (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
 388                 /*
 389                  * If the object is a directory and it leads to a modified
 390                  * object (that should be backed up) and for that type of
 391                  * backup the path nodes should be backed up, then return
 392                  * TRUE.
 393                  *
 394                  * This is required by some DMAs like Backup Express, which
 395                  * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
 396                  * for the intermediate directories of a modified object.
 397                  * Other DMAs, like net_backup and net_worker, do not have such
 398                  * requirement.  This requirement makes sense for dump format
 399                  * but for 'tar' format, it does not.  In provision to the
 400                  * NDMP-v4 spec, for 'tar' format the intermediate directories
 401                  * need not to be reported.
 402                  */
 403                 NDMP_LOG(LOG_DEBUG, "p(%lu)", (u_longlong_t)attr->st_ino);
 404                 return (TRUE);
 405         }
 406         if (attr->st_mtime > bksp->bs_ldate) {
 407                 NDMP_LOG(LOG_DEBUG, "m(%lu): %lu > %lu",
 408                     (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
 409                     (uint_t)bksp->bs_ldate);
 410                 return (TRUE);
 411         }
 412         if (attr->st_ctime > bksp->bs_ldate) {
 413                 if (NLP_IGNCTIME(nlp)) {
 414                         NDMP_LOG(LOG_DEBUG, "ign c(%lu): %lu > %lu",
 415                             (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
 416                             (uint_t)bksp->bs_ldate);
 417                         return (FALSE);
 418                 }
 419                 NDMP_LOG(LOG_DEBUG, "c(%lu): %lu > %lu",
 420                     (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
 421                     (uint_t)bksp->bs_ldate);
 422                 return (TRUE);
 423         }
 424         NDMP_LOG(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
 425             (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
 426             (uint_t)attr->st_ctime, (uint_t)bksp->bs_ldate);
 427         return (FALSE);
 428 }
 429 
 430 
 431 /*
 432  * get_acl_info
 433  *
 434  * load up all the access and attribute info
 435  */
 436 static int
 437 get_acl_info(char *name, tlm_acls_t *tlm_acls)
 438 {
 439         int erc;
 440         acl_t *aclp = NULL;
 441         char *acltp;
 442 
 443         erc = lstat64(name, &tlm_acls->acl_attr);
 444         if (erc != 0) {
 445                 NDMP_LOG(LOG_ERR, "Could not find file %s.", name);
 446                 erc = TLM_NO_SOURCE_FILE;
 447                 return (erc);
 448         }
 449         erc = acl_get(name, ACL_NO_TRIVIAL, &aclp);
 450         if (erc != 0) {
 451                 NDMP_LOG(LOG_DEBUG,
 452                     "Could not read ACL for file [%s]", name);
 453                 erc = TLM_NO_SOURCE_FILE;
 454                 return (erc);
 455         }
 456         if (aclp && (acltp = acl_totext(aclp,
 457             ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
 458                 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
 459                     TLM_MAX_ACL_TXT);
 460                 acl_free(aclp);
 461                 free(acltp);
 462         }
 463         return (erc);
 464 }
 465 /*
 466  * get_dir_acl_info
 467  *
 468  * load up all ACL and attr info about a directory
 469  */
 470 static int
 471 get_dir_acl_info(char *dir, tlm_acls_t *tlm_acls, tlm_job_stats_t *js)
 472 {
 473         int     erc;
 474         char    *checkpointed_dir;
 475         char    root_dir[TLM_VOLNAME_MAX_LENGTH];
 476         char    *spot;
 477         char    *fil;
 478         acl_t   *aclp = NULL;
 479         char    *acltp;
 480 
 481         checkpointed_dir = ndmp_malloc(TLM_MAX_PATH_NAME);
 482         if (checkpointed_dir == NULL)
 483                 return (-1);
 484 
 485         if (tlm_acls->acl_checkpointed)
 486                 fil = tlm_build_snapshot_name(dir, checkpointed_dir,
 487                     js->js_job_name);
 488         else
 489                 fil = dir;
 490         erc = lstat64(fil, &tlm_acls->acl_attr);
 491         if (erc != 0) {
 492                 NDMP_LOG(LOG_ERR, "Could not find directory %s.", dir);
 493                 free(checkpointed_dir);
 494                 return (-1);
 495         }
 496 
 497         spot = strchr(&fil[1], '/');
 498         if (spot == NULL) {
 499                 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
 500         } else {
 501                 *spot = 0;
 502                 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
 503                 *spot = '/';
 504         }
 505         if (strcmp(root_dir, tlm_acls->acl_root_dir) != 0) {
 506                 struct stat64 attr;
 507 
 508                 erc = lstat64(root_dir, &attr);
 509                 if (erc != 0) {
 510                         NDMP_LOG(LOG_ERR, "Cannot find root directory %s.",
 511                             root_dir);
 512                         free(checkpointed_dir);
 513                         return (-1);
 514                 }
 515                 (void) strlcpy(tlm_acls->acl_root_dir, root_dir,
 516                     TLM_VOLNAME_MAX_LENGTH);
 517         }
 518         erc = acl_get(fil, ACL_NO_TRIVIAL, &aclp);
 519         if (erc != 0) {
 520                 NDMP_LOG(LOG_DEBUG,
 521                     "Could not read metadata for directory [%s]", dir);
 522                 free(checkpointed_dir);
 523                 return (-1);
 524         }
 525         if (aclp && (acltp = acl_totext(aclp,
 526             ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
 527                 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
 528                     TLM_MAX_ACL_TXT);
 529                 acl_free(aclp);
 530                 free(acltp);
 531         }
 532 
 533         free(checkpointed_dir);
 534         return (0);
 535 }
 536 
 537 /*
 538  * backup_dir
 539  *
 540  * Create a TAR entry record for a directory
 541  */
 542 static int
 543 backup_dir(char *dir, tlm_acls_t *tlm_acls,
 544     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
 545     bk_selector_t *bksp)
 546 {
 547         int erc;
 548 
 549         NDMP_LOG(LOG_DEBUG, "\"%s\"", dir);
 550 
 551         erc = get_dir_acl_info(dir, tlm_acls, job_stats);
 552         if (erc != 0) {
 553                 NDMP_LOG(LOG_DEBUG,
 554                     "Could not read directory info for %s", dir);
 555                 job_stats->js_errors++;
 556         } else {
 557                 /*
 558                  * See if the directory must be backed up.
 559                  */
 560                 if (bksp && !(*bksp->bs_fn)(bksp, &tlm_acls->acl_attr)) {
 561                         NDMP_LOG(LOG_DEBUG, "[%s] dir skipped", dir);
 562                         return (erc);
 563                 }
 564 
 565                 if (tm_tar_ops.tm_putdir != NULL)
 566                         (void) (tm_tar_ops.tm_putdir)(dir, tlm_acls,
 567                             local_commands, job_stats);
 568         }
 569 
 570         return (erc);
 571 }
 572 
 573 
 574 /*
 575  * backup_file
 576  *
 577  * Create a TAR record entry for a file
 578  */
 579 static longlong_t
 580 backup_file(char *dir, char *name, tlm_acls_t *tlm_acls,
 581     tlm_commands_t *commands, tlm_cmd_t *local_commands,
 582     tlm_job_stats_t *job_stats, bk_selector_t *bksp)
 583 {
 584 
 585         int erc;
 586         char buf[TLM_MAX_PATH_NAME];
 587         longlong_t rv;
 588 
 589         NDMP_LOG(LOG_DEBUG, "\"%s/%s\"", dir, name);
 590 
 591         (void) strlcpy(buf, dir, sizeof (buf));
 592         (void) strlcat(buf, "/", sizeof (buf));
 593         (void) strlcat(buf, name, sizeof (buf));
 594 
 595         /*
 596          * get_acl_info extracts file handle, attributes and ACLs of the file.
 597          * This is not efficient when the attributes and file handle of
 598          * the file is already known.
 599          */
 600         erc = get_acl_info(buf, tlm_acls);
 601         if (erc != TLM_NO_ERRORS) {
 602                 NDMP_LOG(LOG_ERR, "Could not open file %s/%s.", dir, name);
 603                 return (-ENOENT);
 604         }
 605 
 606         /* Should the file be backed up? */
 607         if (!bksp) {
 608                 NDMP_LOG(LOG_DEBUG,
 609                     "[%s/%s] has no selection criteria", dir, name);
 610 
 611         } else if (!((*bksp->bs_fn)(bksp, &tlm_acls->acl_attr))) {
 612                 NDMP_LOG(LOG_DEBUG, "[%s/%s] file skipped", dir, name);
 613                 return (0);
 614         }
 615 
 616         /* Only the regular files and symbolic links can be backed up. */
 617         if (!S_ISLNK(tlm_acls->acl_attr.st_mode) &&
 618             !S_ISREG(tlm_acls->acl_attr.st_mode)) {
 619                 NDMP_LOG(LOG_DEBUG,
 620                     "Warning: skip backing up [%s][%s]", dir, name);
 621                 return (-EINVAL);
 622         }
 623 
 624 
 625         if (tm_tar_ops.tm_putfile != NULL)
 626                 rv = (tm_tar_ops.tm_putfile)(dir, name, tlm_acls, commands,
 627                     local_commands, job_stats);
 628 
 629         return (rv);
 630 }
 631 
 632 
 633 
 634 /*
 635  * backup_work
 636  *
 637  * Start the NDMP backup (V2 only).
 638  */
 639 int


 641     ndmp_run_args_t *np, tlm_commands_t *commands,
 642     ndmp_lbr_params_t *nlp)
 643 {
 644         struct full_dir_info dir_info; /* the blob to push/pop with cstack_t */
 645         struct full_dir_info *t_dir_info, *p_dir_info;
 646         struct stat64 ret_attr; /* attributes of current file name */
 647         fs_fhandle_t ret_fh;
 648         char *first_name; /* where the first name is located */
 649         char *dname;
 650         int erc;
 651         int retval;
 652         cstack_t *stk;
 653         unsigned long fileid;
 654         tlm_acls_t tlm_acls;
 655         int dname_size;
 656         longlong_t fsize;
 657         bk_selector_t bks;
 658         tlm_cmd_t *local_commands;
 659         long    dpos;
 660 
 661         NDMP_LOG(LOG_DEBUG, "nr_chkpnted %d nr_ldate: %u bk_path: \"%s\"",
 662             NLP_ISCHKPNTED(nlp), nlp->nlp_ldate, bk_path);
 663 
 664         /* Get every name in this directory */
 665         dname = ndmp_malloc(TLM_MAX_PATH_NAME);
 666         if (dname == NULL)
 667                 return (-ENOMEM);
 668 
 669         local_commands = commands->tcs_command;
 670         retval = 0;
 671         (void) memset(&bks, 0, sizeof (bks));
 672         bks.bs_cookie = (void *)nlp;
 673         bks.bs_level = nlp->nlp_clevel;
 674         bks.bs_ldate = nlp->nlp_ldate;
 675         bks.bs_fn = timecmp;
 676 
 677         /*
 678          * should we skip the whole thing?
 679          */
 680         if (tlm_is_excluded("", bk_path, np->nr_excls)) {
 681                 NDMP_LOG(LOG_DEBUG, "%s excluded", bk_path);
 682                 free(dname);
 683                 return (0);
 684         }
 685 
 686         /*
 687          * Search for the top-level file-directory
 688          */
 689         if (NLP_ISCHKPNTED(nlp)) {
 690                 first_name = np->nr_chkp_nm;
 691                 (void) strlcpy(first_name, bk_path, TLM_MAX_PATH_NAME);
 692         } else {
 693                 first_name = tlm_build_snapshot_name(bk_path, np->nr_chkp_nm,
 694                     nlp->nlp_jstat->js_job_name);
 695         }
 696 
 697         (void) memset(&ret_fh, 0, sizeof (ret_fh));
 698         erc = fs_getstat(first_name, &ret_fh, &ret_attr);
 699         if (erc != 0) {
 700                 NDMP_LOG(LOG_ERR, "Path %s not found.", first_name);
 701                 free(dname);
 702                 return (-EINVAL);
 703         }
 704 
 705         if ((stk = cstack_new()) == NULL) {
 706                 free(dname);
 707                 NDMP_LOG(LOG_DEBUG, "cstack_new failed");
 708                 return (-ENOMEM);
 709         }
 710         (void) strlcpy(dir_info.fd_dir_name, first_name, TLM_MAX_PATH_NAME);
 711         (void) memcpy(&dir_info.fd_dir_fh, &ret_fh, sizeof (fs_fhandle_t));
 712         p_dir_info = dup_dir_info(&dir_info);
 713 
 714         /*
 715          * Push the first name onto the stack so that we can pop it back
 716          * off as part of the normal cycle
 717          */
 718         if (cstack_push(stk, p_dir_info, 0)) {
 719                 free(dname);
 720                 free(p_dir_info);
 721                 cstack_delete(stk);
 722                 NDMP_LOG(LOG_DEBUG, "cstack_push failed");
 723                 return (-ENOMEM);
 724         }
 725 
 726         (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
 727         /*
 728          * Did NDMP create a checkpoint?
 729          */
 730         if (NLP_ISCHKPNTED(nlp) || fs_is_rdonly(bk_path)) {
 731                 tlm_acls.acl_checkpointed = FALSE;
 732         } else {
 733                 /* Use the checkpoint created by NDMP */
 734                 tlm_acls.acl_checkpointed = TRUE;
 735         }
 736 
 737         /*
 738          * This is level-backup.  It never resets the archive bit.
 739          */
 740         tlm_acls.acl_clear_archive = FALSE;
 741 
 742         NDMP_LOG(LOG_DEBUG, "acls.chkpnt: %c acls.clear_arcbit: %c",
 743             NDMP_YORN(tlm_acls.acl_checkpointed),
 744             NDMP_YORN(tlm_acls.acl_clear_archive));
 745 
 746         while (commands->tcs_reader == TLM_BACKUP_RUN &&
 747             local_commands->tc_reader == TLM_BACKUP_RUN &&
 748             cstack_pop(stk, (void **)&p_dir_info, 0) == 0) {
 749 
 750                 if (NLP_ISCHKPNTED(nlp))
 751                         (void) strlcpy(np->nr_unchkp_nm,
 752                             p_dir_info->fd_dir_name, TLM_MAX_PATH_NAME);
 753                 else
 754                         (void) tlm_remove_checkpoint(p_dir_info->fd_dir_name,
 755                             np->nr_unchkp_nm);
 756 
 757                 (void) backup_dir(np->nr_unchkp_nm, &tlm_acls, local_commands,
 758                     job_stats, &bks);
 759 
 760 
 761                 while (commands->tcs_reader == TLM_BACKUP_RUN &&
 762                     local_commands->tc_reader == TLM_BACKUP_RUN) {
 763 
 764                         dname_size = TLM_MAX_PATH_NAME - 1;
 765 
 766                         NDMP_LOG(LOG_DEBUG,
 767                             "dir_name: %s", p_dir_info->fd_dir_name);
 768 
 769                         (void) memset(&ret_fh, 0, sizeof (ret_fh));
 770                         erc = fs_readdir(&p_dir_info->fd_dir_fh,
 771                             p_dir_info->fd_dir_name, &dpos,
 772                             dname, &dname_size, &ret_fh, &ret_attr);
 773                         if (erc == 0) {
 774                                 fileid = ret_fh.fh_fid;
 775                         } else {
 776                                 NDMP_LOG(LOG_DEBUG,
 777                                     "Filesystem readdir in [%s]",
 778                                     p_dir_info->fd_dir_name);
 779                                 retval = -ENOENT;
 780                                 break;
 781                         }
 782 
 783                         /* an empty name size marks the end of the list */
 784                         if (dname_size == 0)
 785                                 break;
 786                         dname[dname_size] = '\0';
 787 
 788                         NDMP_LOG(LOG_DEBUG, "dname: \"%s\"", dname);
 789 
 790                         /*
 791                          * If name refers to a directory, push its file
 792                          *   handle onto the stack  (skip "." and "..").
 793                          */
 794                         if (rootfs_dot_or_dotdot(dname)) {
 795                                 fileid = 0;
 796                                 continue;
 797                         }
 798 
 799                         /*
 800                          * Skip the:
 801                          * non-dir entries which should not be backed up
 802                          * Or
 803                          * dir-type entries which have have nothing under
 804                          * their hierarchy to be backed up.
 805                          */
 806                         if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)fileid)) {
 807                                 NDMP_LOG(LOG_DEBUG, "Skipping %s/%s",
 808                                     p_dir_info->fd_dir_name, dname);
 809                                 fileid = 0;
 810                                 continue;
 811                         }
 812 
 813                         if (tlm_is_excluded(np->nr_unchkp_nm, dname,
 814                             np->nr_excls)) {
 815                                 fileid = 0;
 816                                 continue;
 817                         }
 818                         if (S_ISDIR(ret_attr.st_mode)) {
 819                                 /*
 820                                  * only directories get pushed onto this stack,
 821                                  * so we do not have to test for regular files.
 822                                  */
 823                                 t_dir_info = tlm_new_dir_info(&ret_fh,
 824                                     p_dir_info->fd_dir_name, dname);
 825                                 if (t_dir_info == NULL) {
 826                                         NDMP_LOG(LOG_DEBUG,
 827                                             "While backing up [%s][%s]",
 828                                             p_dir_info->fd_dir_name, dname);
 829                                 } else if (cstack_push(stk, t_dir_info,
 830                                     0) != 0) {
 831                                         NDMP_LOG(LOG_DEBUG,
 832                                             "No enough memory stack_push");
 833                                         retval = -ENOMEM;
 834                                         break;
 835                                 }
 836                         } else if (S_ISREG(ret_attr.st_mode) ||
 837                             S_ISLNK(ret_attr.st_mode)) {
 838 
 839                                 fsize = backup_file(np->nr_unchkp_nm, dname,
 840                                     &tlm_acls, commands, local_commands,
 841                                     job_stats, &bks);
 842 
 843                                 if (fsize >= 0) {
 844                                         job_stats->js_files_so_far++;
 845                                         job_stats->js_bytes_total += fsize;
 846                                 } else
 847                                         job_stats->js_errors++;
 848                                 fileid = 0;
 849                         }
 850                 }
 851                 fileid = 0;


 901         }
 902         return (rv);
 903 }
 904 
 905 
 906 /*
 907  * ndmp_backup_reader
 908  *
 909  * Backup reader thread which uses backup_work to read and TAR
 910  * the files/dirs to be backed up (V2 only)
 911  */
 912 static int
 913 ndmp_backup_reader(tlm_commands_t *commands, ndmp_lbr_params_t *nlp,
 914     char *job_name)
 915 {
 916         int retval;
 917         ndmp_run_args_t np;
 918         tlm_job_stats_t *job_stats;
 919         tlm_cmd_t *local_commands;
 920 
 921         NDMP_LOG(LOG_DEBUG, "bk_path: \"%s\"", nlp->nlp_backup_path);
 922 
 923         local_commands = commands->tcs_command;
 924         (void) memset(&np, 0, sizeof (np));
 925         if (!malloc_paths(&np))
 926                 return (-1);
 927         local_commands->tc_ref++;
 928         commands->tcs_reader_count++;
 929 
 930         job_stats = tlm_ref_job_stats(job_name);
 931 
 932         retval = backup_work(nlp->nlp_backup_path, job_stats, &np,
 933             commands, nlp);
 934         write_tar_eof(local_commands);
 935 
 936         commands->tcs_reader_count--;
 937         local_commands->tc_writer = TLM_STOP;
 938         tlm_release_reader_writer_ipc(local_commands);
 939         tlm_un_ref_job_stats(job_name);
 940 
 941         free_paths(&np);


 945 
 946 
 947 /*
 948  * ndmp_tar_writer
 949  *
 950  * The backup writer thread that writes the TAR records to the
 951  * tape media (V2 only)
 952  */
 953 int
 954 ndmp_tar_writer(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
 955     tlm_commands_t *cmds)
 956 {
 957         int bidx, nw;
 958         int err;
 959         tlm_buffer_t *buf;
 960         tlm_buffers_t *bufs;
 961         tlm_cmd_t *lcmd;        /* Local command */
 962 
 963         err = 0;
 964         if (session == NULL) {
 965                 NDMP_LOG(LOG_DEBUG, "session == NULL");
 966                 err = -1;
 967         } else if (mod_params == NULL) {
 968                 NDMP_LOG(LOG_DEBUG, "mod_params == NULL");
 969                 err = -1;
 970         } else if (cmds == NULL) {
 971                 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
 972                 err = -1;
 973         }
 974 
 975         if (err != 0)
 976                 return (err);
 977 
 978         lcmd = cmds->tcs_command;
 979         bufs = lcmd->tc_buffers;
 980 
 981         lcmd->tc_ref++;
 982         cmds->tcs_writer_count++;
 983 
 984         nw = 0;
 985         buf = tlm_buffer_out_buf(bufs, &bidx);
 986         while (cmds->tcs_writer != (int)TLM_ABORT &&
 987             lcmd->tc_writer != (int)TLM_ABORT) {
 988                 if (buf->tb_full) {
 989                         NDMP_LOG(LOG_DEBUG, "w%d", bidx);
 990 
 991                         if (MOD_WRITE(mod_params, buf->tb_buffer_data,
 992                             buf->tb_buffer_size) != 0) {
 993                                 NDMP_LOG(LOG_DEBUG,
 994                                     "Writing buffer %d, pos: %lld",
 995                                     bidx, session->ns_mover.md_position);
 996                                 err = -1;
 997                                 break;
 998                         }
 999 
1000                         tlm_buffer_mark_empty(buf);
1001                         (void) tlm_buffer_advance_out_idx(bufs);
1002                         buf = tlm_buffer_out_buf(bufs, &bidx);
1003                         tlm_buffer_release_out_buf(bufs);
1004                         nw++;
1005                 } else {
1006                         if (lcmd->tc_writer != TLM_BACKUP_RUN) {
1007                                 /* No more data is comming; time to exit. */
1008                                 NDMP_LOG(LOG_DEBUG,
1009                                     "tc_writer!=TLM_BACKUP_RUN; time to exit");
1010                                 break;
1011                         } else {
1012                                 NDMP_LOG(LOG_DEBUG, "W%d", bidx);
1013                                 tlm_buffer_in_buf_timed_wait(bufs, 100);
1014                         }
1015                 }
1016         }
1017 
1018         NDMP_LOG(LOG_DEBUG, "nw: %d", nw);
1019         if (cmds->tcs_writer != (int)TLM_ABORT) {
1020                 NDMP_LOG(LOG_DEBUG, "tcs_writer != TLM_ABORT");
1021         } else {
1022                 NDMP_LOG(LOG_DEBUG, "tcs_writer == TLM_ABORT");
1023         }
1024 
1025         if (lcmd->tc_writer != (int)TLM_ABORT) {
1026                 NDMP_LOG(LOG_DEBUG, "tc_writer != TLM_ABORT");
1027         } else {
1028                 NDMP_LOG(LOG_DEBUG, "tc_writer == TLM_ABORT");
1029         }
1030         cmds->tcs_writer_count--;
1031         lcmd->tc_reader = TLM_STOP;
1032         lcmd->tc_ref--;
1033 
1034         return (err);
1035 }
1036 
1037 
1038 /*
1039  * read_one_buf
1040  *
1041  * Read one buffer from the tape
1042  */
1043 static int
1044 read_one_buf(ndmpd_module_params_t *mod_params, tlm_buffers_t *bufs,
1045     tlm_buffer_t *buf)
1046 {
1047         int rv;
1048 
1049         if ((rv = MOD_READ(mod_params, buf->tb_buffer_data,


1071 ndmp_tar_reader(ndmp_tar_reader_arg_t *argp)
1072 {
1073         int bidx;
1074         int err;
1075         tlm_buffer_t *buf;
1076         tlm_buffers_t *bufs;
1077         tlm_cmd_t *lcmd;        /* Local command */
1078         ndmpd_session_t *session;
1079         ndmpd_module_params_t *mod_params;
1080         tlm_commands_t *cmds;
1081 
1082         if (!argp)
1083                 return (-1);
1084 
1085         session = argp->tr_session;
1086         mod_params = argp->tr_mod_params;
1087         cmds = argp->tr_cmds;
1088 
1089         err = 0;
1090         if (session == NULL) {
1091                 NDMP_LOG(LOG_DEBUG, "session == NULL");
1092                 err = -1;
1093         } else if (cmds == NULL) {
1094                 NDMP_LOG(LOG_DEBUG, "cmds == NULL");
1095                 err = -1;
1096         }
1097 
1098         if (err != 0) {
1099                 tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER);
1100                 return (err);
1101         }
1102 
1103         lcmd = cmds->tcs_command;
1104         bufs = lcmd->tc_buffers;
1105 
1106         lcmd->tc_ref++;
1107         cmds->tcs_reader_count++;
1108 
1109         /*
1110          * Synchronize with our parent thread.
1111          */
1112         tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER);
1113 
1114         buf = tlm_buffer_in_buf(bufs, &bidx);
1115         while (cmds->tcs_reader == TLM_RESTORE_RUN &&
1116             lcmd->tc_reader == TLM_RESTORE_RUN) {
1117 
1118                 if (buf->tb_full) {
1119                         NDMP_LOG(LOG_DEBUG, "R%d", bidx);
1120                         /*
1121                          * The buffer is still full, wait for the consumer
1122                          * thread to use it.
1123                          */
1124                         tlm_buffer_out_buf_timed_wait(bufs, 100);
1125                         buf = tlm_buffer_in_buf(bufs, NULL);
1126                 } else {
1127                         NDMP_LOG(LOG_DEBUG, "r%d", bidx);
1128 
1129                         err = read_one_buf(mod_params, bufs, buf);
1130                         if (err < 0) {
1131                                 NDMP_LOG(LOG_DEBUG,
1132                                     "Reading buffer %d, pos: %lld",
1133                                     bidx, session->ns_mover.md_position);
1134 
1135                                 /* Force the writer to stop. */
1136                                 buf->tb_eot = buf->tb_eof = TRUE;
1137                                 break;
1138                         } else if (err == 1) {
1139                                 NDMP_LOG(LOG_DEBUG,
1140                                     "operation aborted or session terminated");
1141                                 err = 0;
1142                                 break;
1143                         }
1144 
1145                         buf = tlm_buffer_in_buf(bufs, &bidx);
1146                         tlm_buffer_release_in_buf(bufs);
1147                 }
1148         }
1149 
1150         /*
1151          * If the consumer is waiting for us, wake it up so that it detects
1152          * we're quiting.
1153          */
1154         lcmd->tc_writer = TLM_STOP;
1155         tlm_buffer_release_in_buf(bufs);
1156         (void) usleep(1000);
1157 
1158         /*
1159          * Clean up.


1162         lcmd->tc_ref--;
1163         return (err);
1164 }
1165 
1166 
1167 /*
1168  * ndmpd_tar_backup
1169  *
1170  * Check must have been done that backup work directory exists, before
1171  * calling this function.
1172  */
1173 static int
1174 ndmpd_tar_backup(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
1175     ndmp_lbr_params_t *nlp)
1176 {
1177         char jname[TLM_MAX_BACKUP_JOB_NAME];
1178         int err;
1179         tlm_commands_t *cmds;
1180 
1181         if (mod_params->mp_operation != NDMP_DATA_OP_BACKUP) {
1182                 NDMP_LOG(LOG_DEBUG,
1183                     "mod_params->mp_operation != NDMP_DATA_OP_BACKUP");
1184                 err = -1;
1185         } else {
1186                 if (ndmpd_mark_inodes_v2(session, nlp) != 0)
1187                         err = -1;
1188                 else if (ndmp_get_bk_dir_ino(nlp))
1189                         err = -1;
1190                 else
1191                         err = 0;
1192         }
1193 
1194         if (err != 0)
1195                 return (err);
1196 
1197         (void) ndmp_new_job_name(jname);
1198         if (backup_create_structs(session, jname) < 0)
1199                 return (-1);
1200 



1201         nlp->nlp_jstat->js_start_ltime = time(NULL);
1202         nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
1203         nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
1204 
1205         if (!session->ns_data.dd_abort) {
1206 
1207                 cmds = &nlp->nlp_cmds;
1208                 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
1209                 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
1210                 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
1211 
1212                 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
1213                         backup_release_structs(session);
1214                         return (-1);
1215                 }
1216 
1217                 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" started.",
1218                     nlp->nlp_backup_path);
1219 
1220                 err = ndmp_backup_reader(cmds, nlp, jname);
1221                 if (err != 0) {
1222                         backup_release_structs(session);
1223                         NDMP_LOG(LOG_DEBUG, "Launch ndmp_backup_reader: %s",
1224                             strerror(err));
1225                         return (-1);
1226                 }
1227 
1228                 /* Act as the writer thread. */
1229                 err = ndmp_tar_writer(session, mod_params, cmds);
1230 
1231                 nlp->nlp_jstat->js_stop_time = time(NULL);
1232 
1233                 NDMP_LOG(LOG_DEBUG,
1234                     "Runtime [%s] %llu bytes (%llu): %d seconds",
1235                     nlp->nlp_backup_path, session->ns_mover.md_data_written,
1236                     session->ns_mover.md_data_written,
1237                     nlp->nlp_jstat->js_stop_time -
1238                     nlp->nlp_jstat->js_start_ltime);
1239                 MOD_LOG(mod_params,
1240                     "Runtime [%s] %llu bytes (%llu): %d seconds",
1241                     nlp->nlp_backup_path, session->ns_mover.md_data_written,
1242                     session->ns_mover.md_data_written,
1243                     nlp->nlp_jstat->js_stop_time -
1244                     nlp->nlp_jstat->js_start_ltime);
1245 
1246                 if (session->ns_data.dd_abort)
1247                         err = -1;
1248 
1249                 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" finished. (%d)",
1250                     nlp->nlp_backup_path, err);
1251         } else {
1252                 nlp->nlp_jstat->js_stop_time = time(NULL);
1253                 NDMP_LOG(LOG_DEBUG, "Backing up \"%s\" aborted.",
1254                     nlp->nlp_backup_path);
1255                 err = 0;
1256         }
1257 
1258         backup_release_structs(session);
1259         return (err);
1260 }
1261 
1262 
1263 /*
1264  * ndmpd_tar_restore
1265  *
1266  * Restore function that launches TAR reader thread to read from the
1267  * tape and writes the extracted files/dirs to the filesystem
1268  */
1269 static int
1270 ndmpd_tar_restore(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
1271     ndmp_lbr_params_t *nlp)
1272 {
1273         char jname[TLM_MAX_BACKUP_JOB_NAME];
1274         char *rspath;
1275         int err;
1276         tlm_commands_t *cmds;
1277         ndmp_tar_reader_arg_t arg;
1278         tlm_backup_restore_arg_t tlm_arg;
1279         ndmp_name *ent;
1280         pthread_t rdtp, wrtp;
1281         int i;
1282 
1283         if (mod_params->mp_operation != NDMP_DATA_OP_RECOVER) {
1284                 NDMP_LOG(LOG_DEBUG,
1285                     "mod_params->mp_operation != NDMP_DATA_OP_RECOVER");
1286                 return (-1);
1287         }
1288 
1289         if (nlp->nlp_restore_path[0] != '\0')
1290                 rspath = nlp->nlp_restore_path;
1291         else if (nlp->nlp_restore_bk_path[0] != '\0')
1292                 rspath = nlp->nlp_restore_bk_path;
1293         else
1294                 rspath = "";
1295 
1296         (void) ndmp_new_job_name(jname);
1297         if (restore_create_structs(session, jname) < 0)
1298                 return (-1);




1299 
1300         nlp->nlp_jstat->js_start_ltime = time(NULL);
1301         nlp->nlp_jstat->js_start_time = time(NULL);
1302 
1303         if (!session->ns_data.dd_abort) {
1304                 cmds = &nlp->nlp_cmds;
1305                 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
1306                 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
1307                 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
1308 
1309                 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" started.", rspath);
1310                 NDMP_LOG(LOG_DEBUG, "Restoring from %s tape(s).",
1311                     ndmp_data_get_mover_mode(session));
1312 
1313                 arg.tr_session = session;
1314                 arg.tr_mod_params = mod_params;
1315                 arg.tr_cmds = cmds;
1316 
1317                 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
1318                     (void *)&arg);
1319                 if (err == 0) {
1320                         tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
1321                 } else {
1322                         NDMP_LOG(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
1323                         return (-1);
1324                 }
1325 
1326                 if (!ndmp_check_utf8magic(cmds->tcs_command)) {
1327                         NDMP_LOG(LOG_DEBUG, "UTF8Magic not found!");
1328                 } else {
1329                         NDMP_LOG(LOG_DEBUG, "UTF8Magic found");
1330                 }
1331 
1332                 (void) memset(&tlm_arg, 0, sizeof (tlm_backup_restore_arg_t));
1333                 (void) pthread_barrier_init(&tlm_arg.ba_barrier, 0, 2);
1334 
1335                 /*
1336                  * Set up restore parameters
1337                  */
1338                 tlm_arg.ba_commands = cmds;
1339                 tlm_arg.ba_cmd = cmds->tcs_command;
1340                 tlm_arg.ba_job = nlp->nlp_jstat->js_job_name;
1341                 tlm_arg.ba_dir = nlp->nlp_restore_path;
1342                 for (i = 0; i < nlp->nlp_nfiles; i++) {
1343                         ent = (ndmp_name *)MOD_GETNAME(mod_params, i);
1344                         tlm_arg.ba_sels[i] = ent->name;
1345                 }

1346 
1347 
1348                 if (tm_tar_ops.tm_getfile != NULL) {
1349                         err = pthread_create(&wrtp, NULL,
1350                             (funct_t)tm_tar_ops.tm_getfile, (void *)&tlm_arg);
1351                 } else {
1352                         (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1353                         NDMP_LOG(LOG_DEBUG,
1354                             "Thread create tm_getfile: ops NULL");
1355                         return (-1);
1356                 }
1357                 if (err == 0) {
1358                         (void) pthread_barrier_wait(&tlm_arg.ba_barrier);
1359                 } else {
1360                         (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1361                         NDMP_LOG(LOG_DEBUG, "thread create tm_getfile: %m");
1362                         return (-1);
1363                 }
1364 
1365                 (void) pthread_join(rdtp, NULL);
1366                 (void) pthread_join(wrtp, NULL);
1367                 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1368 
1369                 nlp->nlp_jstat->js_stop_time = time(NULL);
1370 
1371                 /* Send the list of un-recovered files/dirs to the client.  */
1372                 (void) send_unrecovered_list(mod_params, nlp);
1373 
1374                 ndmp_stop_local_reader(session, cmds);
1375                 ndmp_wait_for_reader(cmds);
1376                 ndmp_stop_remote_reader(session);
1377                 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
1378                     rspath, err);
1379         } else {
1380                 nlp->nlp_jstat->js_stop_time = time(NULL);
1381 
1382                 /* nothing restored. */
1383                 (void) send_unrecovered_list(mod_params, nlp);
1384                 NDMP_LOG(LOG_DEBUG, "Restoring to \"%s\" aborted.",
1385                     rspath);
1386                 err = -1;
1387         }
1388 
1389         NDMP_FREE(nlp->nlp_restore_path);
1390         backup_release_structs(session);
1391 
1392         return (err);
1393 }
1394 
1395 
1396 /*
1397  * prefixdir
1398  *
1399  * Extract the path for a given full path entry
1400  */
1401 static char *
1402 prefixdir(char *dir, char *suffix)
1403 {
1404         static char tmp[TLM_MAX_PATH_NAME];


1489  * Correct the entries in the restore list by appending the appropriate
1490  * path to them
1491  */
1492 static int
1493 correct_ents(ndmpd_module_params_t *params, int n, char *bkpath)
1494 {
1495         char *cp, *pathname;
1496         int i, len, rv;
1497         ndmp_name *ent;
1498 
1499         if ((pathname = ndmp_malloc(TLM_MAX_PATH_NAME)) == NULL) {
1500                 MOD_LOG(params, "Error: insufficient memory.\n");
1501                 return (-1);
1502         }
1503 
1504         rv = 0;
1505         /* Append the backup path to all the "ent[].name"s. */
1506         for (i = 0; i < n; i++) {
1507                 ent = (ndmp_name *)MOD_GETNAME(params, i);
1508 
1509                 NDMP_LOG(LOG_DEBUG,
1510                     "Old: ent[%d].name: \"%s\"", i, ent->name);
1511                 NDMP_LOG(LOG_DEBUG,
1512                     "Old: ent[%d].dest: \"%s\"", i, ent->dest);
1513 
1514                 /* remove trailing slash */
1515                 len = strlen(ent->name);
1516                 if (ent->name[len - 1] == '/')
1517                         ent->name[len - 1] = '\0';
1518 
1519                 if (!tlm_cat_path(pathname, bkpath, ent->name)) {
1520                         MOD_LOG(params, "Error: path too long.\n");
1521                         rv = -1;
1522                         break;
1523                 }
1524 
1525                 /* Make a copy of the new string and save it in ent->name. */
1526                 cp = strdup(pathname);
1527                 if (cp == NULL) {
1528                         MOD_LOG(params, "Error: insufficient memory.\n");
1529                         rv = -1;
1530                         break;
1531                 }
1532                 free(ent->name);
1533                 ent->name = cp;
1534 
1535                 NDMP_LOG(LOG_DEBUG,
1536                     "New: ent[%d].name: \"%s\"", i, ent->name);
1537         }
1538 
1539         free(pathname);
1540         return (rv);
1541 }
1542 
1543 
1544 /*
1545  * check_restore_paths
1546  *
1547  * Go through the restore list and check the validity of the
1548  * restore path.
1549  */
1550 static int
1551 check_restore_paths(ndmpd_module_params_t *params, int n, char *rspath)
1552 {
1553         int i, rv;
1554         ndmp_name *ent;
1555 
1556         rv = 0;
1557         if (rspath != NULL && *rspath != '\0') {
1558                 NDMP_LOG(LOG_DEBUG, "rspath: \"%s\"", rspath);
1559                 if (!fs_volexist(rspath)) {
1560                         MOD_LOG(params,
1561                             "Error: Invalid volume name for restore.");
1562                         rv = -1;
1563                 }
1564         } else {
1565                 for (i = 0; i < n; i++) {
1566                         ent = (ndmp_name *)MOD_GETNAME(params, i);
1567                         NDMP_LOG(LOG_DEBUG,
1568                             "ent[%d].name: \"%s\"", i, ent->name);
1569 
1570                         if (!fs_volexist(ent->name)) {
1571                                 MOD_LOG(params,
1572                                     "Error: Invalid volume name for restore.",
1573                                     ent->name);
1574                                 rv = -1;
1575                                 break;
1576                         }
1577                 }
1578         }
1579 
1580         return (rv);
1581 }
1582 
1583 
1584 /*
1585  * check_backup_dir_validity
1586  *
1587  * Check if the backup directory is valid. Make sure it exists and


1624     ndmpd_module_params_t *params)
1625 {
1626         char *cp;
1627         int rv;
1628         ndmp_lbr_params_t *nlp;
1629 
1630         /* Extract directory to be backed up from env variables */
1631         if ((nlp = ndmp_get_nlp(session)) == NULL) {
1632                 MOD_LOG(params, "Error: Internal error: nlp == NULL.\n");
1633                 return (NDMP_ILLEGAL_ARGS_ERR);
1634         }
1635         if ((nlp->nlp_backup_path = get_backup_path_v2(params)) == NULL)
1636                 return (NDMP_FILE_NOT_FOUND_ERR);
1637 
1638         if ((rv = check_backup_dir_validity(params,
1639             nlp->nlp_backup_path)) != NDMP_NO_ERR)
1640                 return (rv);
1641 
1642         /* Should the st_ctime be ignored when backing up? */
1643         if (ndmp_ignore_ctime) {
1644                 NDMP_LOG(LOG_DEBUG, "ignoring st_ctime");
1645                 NLP_SET(nlp, NLPF_IGNCTIME);
1646         } else
1647                 NLP_UNSET(nlp, NLPF_IGNCTIME);
1648 
1649         /* Should the st_lmtime be ignored when backing up? */
1650         if (ndmp_include_lmtime) {
1651                 NDMP_LOG(LOG_DEBUG, "including st_lmtime");
1652                 NLP_SET(nlp, NLPF_INCLMTIME);
1653         } else
1654                 NLP_UNSET(nlp, NLPF_INCLMTIME);
1655 
1656         NDMP_LOG(LOG_DEBUG, "flags %x", nlp->nlp_flags);
1657 
1658         /* Is backup history requested? */
1659         cp = MOD_GETENV(params, "HIST");
1660         if (cp == NULL) {
1661                 NDMP_LOG(LOG_DEBUG, "env(HIST) not specified");
1662                 NLP_UNSET(nlp, NLPF_FH);
1663         } else {
1664                 NDMP_LOG(LOG_DEBUG, "env(HIST): \"%s\"", cp);
1665 
1666                 if (strchr("t_ty_y", *cp))
1667                         NLP_SET(nlp, NLPF_FH);
1668                 else
1669                         NLP_UNSET(nlp, NLPF_FH);
1670         }
1671 
1672         nlp->nlp_clevel = 0;
1673         /* Is it an incremental backup? */
1674         cp = MOD_GETENV(params, "LEVEL");
1675         if (cp == NULL) {
1676                 NDMP_LOG(LOG_DEBUG,
1677                     "env(LEVEL) not specified, default to 0");
1678         } else if (*cp < '0' || *cp > '9' || *(cp+1) != '\0') {
1679                 NDMP_LOG(LOG_DEBUG, "Invalid backup level '%s'", cp);
1680                 return (NDMP_ILLEGAL_ARGS_ERR);
1681         } else
1682                 nlp->nlp_clevel = *cp - '0';
1683 
1684         /* Extract last backup time from the dumpdates file */
1685         nlp->nlp_llevel = nlp->nlp_clevel;
1686         nlp->nlp_ldate = 0;
1687         if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
1688             &nlp->nlp_ldate) < 0) {
1689                 MOD_LOG(params, "Error: getting dumpdate for %s level %d\n",
1690                     nlp->nlp_backup_path, nlp->nlp_clevel);
1691                 return (NDMP_NO_MEM_ERR);
1692         }
1693 
1694         NDMP_LOG(LOG_DEBUG,
1695             "Date of this level %d on \"%s\": %s",
1696             nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate));
1697         NDMP_LOG(LOG_DEBUG,
1698             "Date of last level %d on \"%s\": %s",
1699             nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate));
1700 
1701         /* Should the dumpdate file be updated? */
1702         cp = MOD_GETENV(params, "UPDATE");
1703         if (cp == NULL) {
1704                 NDMP_LOG(LOG_DEBUG,
1705                     "env(UPDATE) not specified, default to TRUE");
1706                 NLP_SET(nlp, NLPF_UPDATE);
1707         } else {
1708                 NDMP_LOG(LOG_DEBUG, "env(UPDATE): \"%s\"", cp);
1709                 if (strchr("t_ty_y", *cp) != NULL)
1710                         NLP_SET(nlp, NLPF_UPDATE);
1711                 else
1712                         NLP_UNSET(nlp, NLPF_UPDATE);
1713         }
1714 
1715         return (NDMP_NO_ERR);
1716 }
1717 
1718 
1719 
1720 /*
1721  * log_bk_params_v2
1722  *
1723  * Dump the value of the parameters in the log file for debugging.
1724  */
1725 void
1726 log_bk_params_v2(ndmpd_session_t *session, ndmpd_module_params_t *params,
1727     ndmp_lbr_params_t *nlp)
1728 {


1755 same_path(char *s, char *t)
1756 {
1757         boolean_t rv;
1758         int slen, tlen;
1759 
1760         rv = FALSE;
1761         slen = strlen(s);
1762         tlen = strlen(t);
1763         if (slen == tlen && strcmp(s, t) == 0) {
1764                 rv = TRUE;
1765         } else {
1766                 if (slen == tlen - 1) {
1767                         if (strncmp(s, t, slen) == 0 && t[tlen - 1] == '/')
1768                                 rv = TRUE;
1769                 } else if (tlen == slen -1) {
1770                         if (strncmp(s, t, tlen) == 0 && s[slen - 1] == '/')
1771                                 rv = TRUE;
1772                 }
1773         }
1774 
1775         NDMP_LOG(LOG_DEBUG, "rv: %d", rv);
1776         return (rv);
1777 }
1778 
1779 
1780 /*
1781  * ndmp_restore_extract_params
1782  *
1783  * Go through the restore parameters and check them and extract them
1784  * by setting NLP flags and other values.
1785  *
1786  * Parameters:
1787  *
1788  * Returns:
1789  *   0: on success
1790  *  -1: otherwise
1791  */
1792 int
1793 ndmp_restore_extract_params(ndmpd_session_t *session,
1794     ndmpd_module_params_t *params)
1795 {
1796         char *bkpath, *rspath;
1797         ndmp_lbr_params_t *nlp;
1798 
1799         if ((nlp = ndmp_get_nlp(session)) == NULL) {
1800                 NDMP_LOG(LOG_DEBUG, "nlp == NULL");
1801                 return (-1);
1802         }
1803 
1804         /* Extract directory from where the backup was made. */
1805         if ((bkpath = get_backup_path_v2(params)) == NULL)
1806                 return (NDMP_ILLEGAL_ARGS_ERR);
1807 
1808         nlp->nlp_restore_bk_path = bkpath;
1809 
1810         /* The number of the selections. */
1811         if ((nlp->nlp_nfiles = get_nfiles(session, params)) == 0)
1812                 return (NDMP_ILLEGAL_ARGS_ERR);
1813 
1814         NDMP_LOG(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
1815 
1816         if ((rspath = get_restore_dest(params)) == NULL)
1817                 return (NDMP_ILLEGAL_ARGS_ERR);
1818 
1819         if (fs_is_rdonly(rspath)) {
1820                 MOD_LOG(params,
1821                     "Error: Can't restore to a read-only volume: \"%s\"\n",
1822                     rspath);
1823                 return (NDMP_ILLEGAL_ARGS_ERR);
1824         }
1825         if (fs_is_chkpntvol(rspath)) {
1826                 MOD_LOG(params,
1827                     "Error: Can't restore to a checkpoint: \"%s\"\n", rspath);
1828                 return (NDMP_ILLEGAL_ARGS_ERR);
1829         }
1830 
1831         if (same_path(bkpath, rspath))
1832                 rspath = "";
1833 
1834         if ((nlp->nlp_restore_path = strdup(rspath)) == NULL)


1861  */
1862 int
1863 ndmpd_tar_backup_starter(void *arg)
1864 {
1865         ndmpd_module_params_t *mod_params = arg;
1866         int err;
1867         ndmpd_session_t *session;
1868         ndmp_lbr_params_t *nlp;
1869 
1870         session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie);
1871         *(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
1872         ndmp_session_ref(session);
1873 
1874         err = 0;
1875         if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
1876             fs_is_rdonly(nlp->nlp_backup_path) ||
1877             !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
1878                 NLP_SET(nlp, NLPF_CHKPNTED_PATH);
1879         else {
1880                 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
1881                 if (ndmp_create_snapshot(nlp->nlp_backup_path,
1882                     nlp->nlp_jstat->js_job_name) < 0) {
1883                         MOD_LOG(mod_params,
1884                             "Error: creating checkpoint on %s\n",
1885                             nlp->nlp_backup_path);
1886                         /* -1 causes halt reason to become internal error. */
1887                         err = -1;
1888                 }
1889         }
1890 
1891         NDMP_LOG(LOG_DEBUG, "NLPF_CHKPNTED_PATH: %c",
1892             NDMP_YORN(NLP_ISCHKPNTED(nlp)));
1893         NDMP_LOG(LOG_DEBUG, "err: %d, update %c",
1894             err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1895 
1896         if (err == 0) {
1897                 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate,
1898                     nlp->nlp_jstat->js_job_name);
1899                 if (err != 0) {
1900                         NDMP_LOG(LOG_DEBUG, "err %d", err);
1901                 } else {
1902                         log_bk_params_v2(session, mod_params, nlp);
1903                         err = ndmpd_tar_backup(session, mod_params, nlp);
1904                 }
1905         }
1906 
1907         if (nlp->nlp_bkmap >= 0) {
1908                 (void) dbm_free(nlp->nlp_bkmap);
1909                 nlp->nlp_bkmap = -1;
1910         }
1911 
1912         if (!NLP_ISCHKPNTED(nlp))
1913                 (void) ndmp_remove_snapshot(nlp->nlp_backup_path,
1914                     nlp->nlp_jstat->js_job_name);
1915 
1916         NDMP_LOG(LOG_DEBUG, "err %d, update %c",
1917             err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1918 
1919         if (err == 0 && NLP_SHOULD_UPDATE(nlp)) {
1920                 if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1921                     nlp->nlp_cdate) < 0) {
1922                         err = EPERM;
1923                         MOD_LOG(mod_params,
1924                             "Error: updating the dumpdates file on %s\n",
1925                             nlp->nlp_backup_path);
1926                 }
1927         }
1928 
1929         MOD_DONE(mod_params, err);
1930 
1931         /* nlp_params is allocated in start_backup() */
1932         NDMP_FREE(nlp->nlp_params);
1933 
1934         NS_DEC(nbk);
1935         ndmp_session_unref(session);
1936         return (err);


   1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
   4  */
   5 
   6 /*
   7  * BSD 3 Clause License
   8  *
   9  * Copyright (c) 2007, The Storage Networking Industry Association.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *      - Redistributions of source code must retain the above copyright
  15  *        notice, this list of conditions and the following disclaimer.
  16  *
  17  *      - Redistributions in binary form must reproduce the above copyright
  18  *        notice, this list of conditions and the following disclaimer in
  19  *        the documentation and/or other materials provided with the
  20  *        distribution.
  21  *
  22  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  23  *        nor the names of its contributors may be used to endorse or promote
  24  *        products derived from this software without specific prior written
  25  *        permission.
  26  *
  27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37  * POSSIBILITY OF SUCH DAMAGE.
  38  */
  39 /* Copyright (c) 2007, The Storage Networking Industry Association. */
  40 /* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
  41 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
  42 
  43 #include <sys/stat.h>
  44 #include <sys/types.h>
  45 #include <sys/socket.h>
  46 #include <syslog.h>
  47 #include <errno.h>
  48 #include <stdio.h>
  49 #include <string.h>
  50 #include <unistd.h>
  51 #include <time.h>
  52 #include <cstack.h>
  53 #include <dirent.h>
  54 #include <traverse.h>
  55 #include "bitmap.h"
  56 #include "ndmpd.h"
  57 #include "tlm_buffers.h"
  58 
  59 
  60 typedef struct ndmp_run_args {
  61         char *nr_chkp_nm;
  62         char *nr_unchkp_nm;
  63         char **nr_excls;
  64 } ndmp_run_args_t;
  65 
  66 


  69  *
  70  * Allocate the structures before performing backup
  71  *
  72  * Parameters:
  73  *   sesison (input) - session handle
  74  *   jname (input) - backup job name
  75  *
  76  * Returns:
  77  *   0: on success
  78  *  -1: otherwise
  79  */
  80 static int
  81 backup_create_structs(ndmpd_session_t *session, char *jname)
  82 {
  83         int n;
  84         long xfer_size;
  85         ndmp_lbr_params_t *nlp;
  86         tlm_commands_t *cmds;
  87 
  88         if ((nlp = ndmp_get_nlp(session)) == NULL) {

  89                 return (-1);
  90         }
  91 
  92         if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) {

  93                 return (-1);
  94         }
  95 
  96         cmds = &nlp->nlp_cmds;
  97         (void) memset(cmds, 0, sizeof (*cmds));
  98 
  99         xfer_size = ndmp_buffer_get_size(session);
 100         if (xfer_size < 512*KILOBYTE) {
 101                 /*
 102                  * Read multiple of mover_record_size near to 512K.  This
 103                  * will prevent the data being copied in the mover buffer
 104                  * when we write the data.
 105                  */
 106                 if ((n = (512 * KILOBYTE/xfer_size)) <= 0)
 107                         n = 1;
 108                 xfer_size *= n;
 109                 syslog(LOG_DEBUG, "Adjusted read size: %d", xfer_size);
 110         }
 111 
 112         cmds->tcs_command = tlm_create_reader_writer_ipc(TRUE, xfer_size);
 113         if (cmds->tcs_command == NULL) {
 114                 syslog(LOG_ERR, "Error creating ipc buffers");
 115                 tlm_un_ref_job_stats(jname);
 116                 return (-1);
 117         }
 118 
 119         nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
 120             ndmpd_file_history_path,
 121             ndmpd_file_history_dir,
 122             ndmpd_file_history_node);
 123         if (nlp->nlp_logcallbacks == NULL) {
 124                 tlm_release_reader_writer_ipc(cmds->tcs_command);
 125                 tlm_un_ref_job_stats(jname);
 126                 return (-1);
 127         }
 128         nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
 129 
 130         return (0);
 131 }
 132 
 133 
 134 /*


 136  *
 137  * Allocate structures for performing a restore
 138  *
 139  * Parameters:
 140  *   sesison (input) - session handle
 141  *   jname (input) - backup job name
 142  *
 143  * Returns:
 144  *   0: on success
 145  *  -1: otherwise
 146  */
 147 static int
 148 restore_create_structs(ndmpd_session_t *session, char *jname)
 149 {
 150         int i;
 151         long xfer_size;
 152         ndmp_lbr_params_t *nlp;
 153         tlm_commands_t *cmds;
 154 
 155         if ((nlp = ndmp_get_nlp(session)) == NULL) {

 156                 return (-1);
 157         }
 158         if ((nlp->nlp_jstat = tlm_new_job_stats(jname)) == NULL) {

 159                 return (-1);
 160         }
 161 
 162         cmds = &nlp->nlp_cmds;
 163         (void) memset(cmds, 0, sizeof (*cmds));
 164 
 165         xfer_size = ndmp_buffer_get_size(session);
 166         cmds->tcs_command = tlm_create_reader_writer_ipc(FALSE, xfer_size);
 167         if (cmds->tcs_command == NULL) {
 168                 syslog(LOG_ERR, "Error creating ipc buffers");
 169                 tlm_un_ref_job_stats(jname);
 170                 return (-1);
 171         }
 172 
 173         nlp->nlp_logcallbacks = lbrlog_callbacks_init(session,
 174             ndmpd_path_restored, NULL, NULL);
 175         if (nlp->nlp_logcallbacks == NULL) {
 176                 tlm_release_reader_writer_ipc(cmds->tcs_command);
 177                 tlm_un_ref_job_stats(jname);
 178                 return (-1);
 179         }
 180         nlp->nlp_jstat->js_callbacks = (void *)(nlp->nlp_logcallbacks);
 181 
 182         nlp->nlp_restored = ndmp_malloc(sizeof (boolean_t) * nlp->nlp_nfiles);
 183         if (nlp->nlp_restored == NULL) {
 184                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
 185                 tlm_release_reader_writer_ipc(cmds->tcs_command);
 186                 tlm_un_ref_job_stats(jname);
 187                 return (-1);
 188         }


 196 /*
 197  * send_unrecovered_list
 198  *
 199  * Creates a list of restored files
 200  *
 201  * Parameters:
 202  *   params (input) - NDMP parameters
 203  *   nlp (input) - NDMP/LBR parameters
 204  *
 205  * Returns:
 206  *   0: on success
 207  *  -1: otherwise
 208  */
 209 static int
 210 send_unrecovered_list(ndmpd_module_params_t *params, ndmp_lbr_params_t *nlp)
 211 {
 212         int i, rv;
 213         ndmp_name *ent;
 214 
 215         if (params == NULL) {

 216                 return (-1);
 217         }
 218         if (nlp == NULL) {

 219                 return (-1);
 220         }
 221 
 222         rv = 0;
 223         for (i = 0; i < (int)nlp->nlp_nfiles; i++) {
 224                 syslog(LOG_DEBUG, "nlp->nlp_restored[%d]: %s", i,
 225                     nlp->nlp_restored[i] ? "TRUE" : "FALSE");
 226 
 227                 if (!nlp->nlp_restored[i]) {
 228                         ent = (ndmp_name *)MOD_GETNAME(params, i);
 229                         if (ent == NULL) {

 230                                 rv = -1;
 231                                 break;
 232                         }
 233                         if (ent->name == NULL) {

 234                                 rv = -1;
 235                                 break;
 236                         }
 237 
 238                         syslog(LOG_DEBUG, "ent.name: \"%s\"", ent->name);
 239 
 240                         rv = MOD_FILERECOVERD(params, ent->name, ENOENT);
 241                         if (rv < 0)
 242                                 break;
 243                 }
 244         }
 245 
 246         return (rv);
 247 }
 248 
 249 
 250 /*
 251  * backup_release_structs
 252  *
 253  * Deallocated the NDMP/LBR specific parameters
 254  *
 255  * Parameters:
 256  *   session (input) - session handle
 257  *
 258  * Returns:
 259  *   void
 260  */
 261 /*ARGSUSED*/
 262 static void
 263 backup_release_structs(ndmpd_session_t *session)
 264 {
 265         ndmp_lbr_params_t *nlp;
 266         tlm_commands_t *cmds;
 267 
 268         if ((nlp = ndmp_get_nlp(session)) == NULL) {

 269                 return;
 270         }
 271         cmds = &nlp->nlp_cmds;
 272         if (cmds == NULL) {

 273                 return;
 274         }
 275 
 276         if (nlp->nlp_logcallbacks != NULL) {
 277                 lbrlog_callbacks_done(nlp->nlp_logcallbacks);
 278                 nlp->nlp_logcallbacks = NULL;


 279         }
 280 
 281         if (cmds->tcs_command != NULL) {
 282                 if (cmds->tcs_command->tc_buffers != NULL)
 283                         tlm_release_reader_writer_ipc(cmds->tcs_command);


 284                 cmds->tcs_command = NULL;


 285         }
 286 
 287         if (nlp->nlp_bkmap >= 0) {
 288                 (void) dbm_free(nlp->nlp_bkmap);
 289                 nlp->nlp_bkmap = -1;
 290         }
 291 
 292         if (session->ns_data.dd_operation == NDMP_DATA_OP_RECOVER &&
 293             nlp->nlp_restored != NULL) {
 294                 free(nlp->nlp_restored);
 295                 nlp->nlp_restored = NULL;


 296         }
 297 }
 298 
 299 /*
 300  * ndmp_write_utf8magic
 301  *
 302  * Write a magic pattern to the tar header. This is used
 303  * as a crest to indicate that tape belongs to us.
 304  */
 305 int
 306 ndmp_write_utf8magic(tlm_cmd_t *cmd)
 307 {
 308         char *cp;
 309         long actual_size;
 310 
 311         if (cmd->tc_buffers == NULL) {

 312                 return (-1);
 313         }
 314 
 315         cp = tlm_get_write_buffer(RECORDSIZE, &actual_size,
 316             cmd->tc_buffers, TRUE);
 317         if (actual_size < RECORDSIZE) {

 318                 return (-1);
 319         }
 320 
 321         (void) strlcpy(cp, NDMPUTF8MAGIC, RECORDSIZE);
 322         return (0);
 323 }
 324 
 325 
 326 /*
 327  * timecmp
 328  *
 329  * This callback function is used during backup.  It checks
 330  * if the object specified by the 'attr' should be backed
 331  * up or not.
 332  *
 333  * Directories are backed up anyways for dump format.
 334  * If this function is called, then the directory is
 335  * marked in the bitmap vector, it shows that either the
 336  * directory itself is modified or there is something below
 337  * it that will be backed up.


 342  * By setting ndmp_force_bk_dirs global variable to a non-zero
 343  * value, directories are backed up anyways.
 344  *
 345  * Backing up the directories unconditionally, helps
 346  * restoring the metadata of directories as well, when one
 347  * of the objects below them are being restored.
 348  *
 349  * For non-directory objects, if the modification or change
 350  * time of the object is after the date specified by the
 351  * bk_selector_t, the the object must be backed up.
 352  *
 353  */
 354 static boolean_t
 355 timecmp(bk_selector_t *bksp,
 356                 struct stat64 *attr)
 357 {
 358         ndmp_lbr_params_t *nlp;
 359 
 360         nlp = (ndmp_lbr_params_t *)bksp->bs_cookie;
 361         if (S_ISDIR(attr->st_mode) && ndmp_force_bk_dirs) {


 362                 return (TRUE);
 363         }
 364         if (S_ISDIR(attr->st_mode) &&
 365             dbm_getone(nlp->nlp_bkmap, (u_longlong_t)attr->st_ino) &&
 366             ((NLP_ISDUMP(nlp) && ndmp_dump_path_node) ||
 367             (NLP_ISTAR(nlp) && ndmp_tar_path_node))) {
 368                 /*
 369                  * If the object is a directory and it leads to a modified
 370                  * object (that should be backed up) and for that type of
 371                  * backup the path nodes should be backed up, then return
 372                  * TRUE.
 373                  *
 374                  * This is required by some DMAs like Backup Express, which
 375                  * needs to receive ADD_NODE (for dump) or ADD_PATH (for tar)
 376                  * for the intermediate directories of a modified object.
 377                  * Other DMAs, like net_backup and net_worker, do not have such
 378                  * requirement.  This requirement makes sense for dump format
 379                  * but for 'tar' format, it does not.  In provision to the
 380                  * NDMP-v4 spec, for 'tar' format the intermediate directories
 381                  * need not to be reported.
 382                  */
 383                 syslog(LOG_DEBUG, "p(%lu)", (u_longlong_t)attr->st_ino);
 384                 return (TRUE);
 385         }
 386         if (attr->st_mtime > bksp->bs_ldate) {
 387                 syslog(LOG_DEBUG, "m(%lu): %lu > %lu",
 388                     (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
 389                     (uint_t)bksp->bs_ldate);
 390                 return (TRUE);
 391         }
 392         if (attr->st_ctime > bksp->bs_ldate) {
 393                 if (NLP_IGNCTIME(nlp)) {
 394                         syslog(LOG_DEBUG, "ign c(%lu): %lu > %lu",
 395                             (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
 396                             (uint_t)bksp->bs_ldate);
 397                         return (FALSE);
 398                 }
 399                 syslog(LOG_DEBUG, "c(%lu): %lu > %lu",
 400                     (uint_t)attr->st_ino, (uint_t)attr->st_ctime,
 401                     (uint_t)bksp->bs_ldate);
 402                 return (TRUE);
 403         }
 404         syslog(LOG_DEBUG, "mc(%lu): (%lu,%lu) < %lu",
 405             (uint_t)attr->st_ino, (uint_t)attr->st_mtime,
 406             (uint_t)attr->st_ctime, (uint_t)bksp->bs_ldate);
 407         return (FALSE);
 408 }
 409 
 410 
 411 /*
 412  * get_acl_info
 413  *
 414  * load up all the access and attribute info
 415  */
 416 static int
 417 get_acl_info(char *name, tlm_acls_t *tlm_acls)
 418 {
 419         int erc;
 420         acl_t *aclp = NULL;
 421         char *acltp;
 422 
 423         erc = lstat64(name, &tlm_acls->acl_attr);
 424         if (erc != 0) {
 425                 syslog(LOG_ERR, "Could not find file %s.", name);
 426                 erc = TLM_NO_SOURCE_FILE;
 427                 return (erc);
 428         }
 429         erc = acl_get(name, ACL_NO_TRIVIAL, &aclp);
 430         if (erc != 0) {
 431                 syslog(LOG_DEBUG,
 432                     "Could not read ACL for file [%s]", name);
 433                 erc = TLM_NO_SOURCE_FILE;
 434                 return (erc);
 435         }
 436         if (aclp && (acltp = acl_totext(aclp,
 437             ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
 438                 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
 439                     TLM_MAX_ACL_TXT);
 440                 acl_free(aclp);
 441                 free(acltp);
 442         }
 443         return (erc);
 444 }
 445 /*
 446  * get_dir_acl_info
 447  *
 448  * load up all ACL and attr info about a directory
 449  */
 450 static int
 451 get_dir_acl_info(char *dir, tlm_acls_t *tlm_acls, tlm_job_stats_t *js)
 452 {
 453         int     erc;
 454         char    *checkpointed_dir;
 455         char    root_dir[TLM_VOLNAME_MAX_LENGTH];
 456         char    *spot;
 457         char    *fil;
 458         acl_t   *aclp = NULL;
 459         char    *acltp;
 460 
 461         checkpointed_dir = ndmp_malloc(TLM_MAX_PATH_NAME);
 462         if (checkpointed_dir == NULL)
 463                 return (-1);
 464 
 465         if (tlm_acls->acl_checkpointed)
 466                 fil = tlm_build_snapshot_name(dir, checkpointed_dir,
 467                     js->js_job_name);
 468         else
 469                 fil = dir;
 470         erc = lstat64(fil, &tlm_acls->acl_attr);
 471         if (erc != 0) {
 472                 syslog(LOG_ERR, "Could not find directory %s.", dir);
 473                 free(checkpointed_dir);
 474                 return (-1);
 475         }
 476 
 477         spot = strchr(&fil[1], '/');
 478         if (spot == NULL) {
 479                 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
 480         } else {
 481                 *spot = 0;
 482                 (void) strlcpy(root_dir, fil, TLM_VOLNAME_MAX_LENGTH);
 483                 *spot = '/';
 484         }
 485         if (strcmp(root_dir, tlm_acls->acl_root_dir) != 0) {
 486                 struct stat64 attr;
 487 
 488                 erc = lstat64(root_dir, &attr);
 489                 if (erc != 0) {
 490                         syslog(LOG_ERR, "Cannot find root directory %s.",
 491                             root_dir);
 492                         free(checkpointed_dir);
 493                         return (-1);
 494                 }
 495                 (void) strlcpy(tlm_acls->acl_root_dir, root_dir,
 496                     TLM_VOLNAME_MAX_LENGTH);
 497         }
 498         erc = acl_get(fil, ACL_NO_TRIVIAL, &aclp);
 499         if (erc != 0) {
 500                 syslog(LOG_DEBUG,
 501                     "Could not read metadata for directory [%s]", dir);
 502                 free(checkpointed_dir);
 503                 return (-1);
 504         }
 505         if (aclp && (acltp = acl_totext(aclp,
 506             ACL_APPEND_ID | ACL_SID_FMT | ACL_COMPACT_FMT)) != NULL) {
 507                 (void) strlcpy(tlm_acls->acl_info.attr_info, acltp,
 508                     TLM_MAX_ACL_TXT);
 509                 acl_free(aclp);
 510                 free(acltp);
 511         }
 512 
 513         free(checkpointed_dir);
 514         return (0);
 515 }
 516 
 517 /*
 518  * backup_dir
 519  *
 520  * Create a TAR entry record for a directory
 521  */
 522 static int
 523 backup_dir(char *dir, tlm_acls_t *tlm_acls,
 524     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
 525     bk_selector_t *bksp)
 526 {
 527         int erc;
 528 


 529         erc = get_dir_acl_info(dir, tlm_acls, job_stats);
 530         if (erc != 0) {
 531                 syslog(LOG_ERR,
 532                     "Could not read directory info for %s", dir);
 533                 job_stats->js_errors++;
 534         } else {
 535                 /*
 536                  * See if the directory must be backed up.
 537                  */
 538                 if (bksp && !(*bksp->bs_fn)(bksp, &tlm_acls->acl_attr)) {
 539                         syslog(LOG_DEBUG, "[%s] dir skipped", dir);
 540                         return (erc);
 541                 }
 542 
 543                 if (tm_tar_ops.tm_putdir != NULL)
 544                         (void) (tm_tar_ops.tm_putdir)(dir, tlm_acls,
 545                             local_commands, job_stats);
 546         }
 547 
 548         return (erc);
 549 }
 550 
 551 
 552 /*
 553  * backup_file
 554  *
 555  * Create a TAR record entry for a file
 556  */
 557 static longlong_t
 558 backup_file(char *dir, char *name, tlm_acls_t *tlm_acls,
 559     tlm_commands_t *commands, tlm_cmd_t *local_commands,
 560     tlm_job_stats_t *job_stats, bk_selector_t *bksp)
 561 {
 562 
 563         int erc;
 564         char buf[TLM_MAX_PATH_NAME];
 565         longlong_t rv = -1;
 566 


 567         (void) strlcpy(buf, dir, sizeof (buf));
 568         (void) strlcat(buf, "/", sizeof (buf));
 569         (void) strlcat(buf, name, sizeof (buf));
 570 
 571         /*
 572          * get_acl_info extracts file handle, attributes and ACLs of the file.
 573          * This is not efficient when the attributes and file handle of
 574          * the file is already known.
 575          */
 576         erc = get_acl_info(buf, tlm_acls);
 577         if (erc != TLM_NO_ERRORS) {
 578                 syslog(LOG_ERR, "Could not open file %s/%s.", dir, name);
 579                 return (-ENOENT);
 580         }
 581 
 582         /* Should the file be backed up? */
 583         if (!bksp) {
 584                 syslog(LOG_DEBUG,
 585                     "[%s/%s] has no selection criteria", dir, name);
 586 
 587         } else if (!((*bksp->bs_fn)(bksp, &tlm_acls->acl_attr))) {
 588                 syslog(LOG_DEBUG, "[%s/%s] file skipped", dir, name);
 589                 return (0);
 590         }
 591 
 592         /* Only the regular files and symbolic links can be backed up. */
 593         if (!S_ISLNK(tlm_acls->acl_attr.st_mode) &&
 594             !S_ISREG(tlm_acls->acl_attr.st_mode)) {
 595                 syslog(LOG_DEBUG,
 596                     "Warning: skip backing up [%s][%s]", dir, name);
 597                 return (-EINVAL);
 598         }
 599 
 600 
 601         if (tm_tar_ops.tm_putfile != NULL)
 602                 rv = (tm_tar_ops.tm_putfile)(dir, name, tlm_acls, commands,
 603                     local_commands, job_stats);
 604 
 605         return (rv);
 606 }
 607 
 608 
 609 
 610 /*
 611  * backup_work
 612  *
 613  * Start the NDMP backup (V2 only).
 614  */
 615 int


 617     ndmp_run_args_t *np, tlm_commands_t *commands,
 618     ndmp_lbr_params_t *nlp)
 619 {
 620         struct full_dir_info dir_info; /* the blob to push/pop with cstack_t */
 621         struct full_dir_info *t_dir_info, *p_dir_info;
 622         struct stat64 ret_attr; /* attributes of current file name */
 623         fs_fhandle_t ret_fh;
 624         char *first_name; /* where the first name is located */
 625         char *dname;
 626         int erc;
 627         int retval;
 628         cstack_t *stk;
 629         unsigned long fileid;
 630         tlm_acls_t tlm_acls;
 631         int dname_size;
 632         longlong_t fsize;
 633         bk_selector_t bks;
 634         tlm_cmd_t *local_commands;
 635         long    dpos;
 636 
 637         syslog(LOG_DEBUG, "nr_chkpnted %d nr_ldate: %u bk_path: \"%s\"",
 638             NLP_ISCHKPNTED(nlp), nlp->nlp_ldate, bk_path);
 639 
 640         /* Get every name in this directory */
 641         dname = ndmp_malloc(TLM_MAX_PATH_NAME);
 642         if (dname == NULL)
 643                 return (-ENOMEM);
 644 
 645         local_commands = commands->tcs_command;
 646         retval = 0;
 647         (void) memset(&bks, 0, sizeof (bks));
 648         bks.bs_cookie = (void *)nlp;
 649         bks.bs_level = nlp->nlp_clevel;
 650         bks.bs_ldate = nlp->nlp_ldate;
 651         bks.bs_fn = timecmp;
 652 
 653         /*
 654          * should we skip the whole thing?
 655          */
 656         if (tlm_is_excluded("", bk_path, np->nr_excls)) {
 657                 syslog(LOG_DEBUG, "%s excluded", bk_path);
 658                 free(dname);
 659                 return (0);
 660         }
 661 
 662         /*
 663          * Search for the top-level file-directory
 664          */
 665         if (NLP_ISCHKPNTED(nlp)) {
 666                 first_name = np->nr_chkp_nm;
 667                 (void) strlcpy(first_name, bk_path, TLM_MAX_PATH_NAME);
 668         } else {
 669                 first_name = tlm_build_snapshot_name(bk_path, np->nr_chkp_nm,
 670                     nlp->nlp_jstat->js_job_name);
 671         }
 672 
 673         (void) memset(&ret_fh, 0, sizeof (ret_fh));
 674         erc = fs_getstat(first_name, &ret_fh, &ret_attr);
 675         if (erc != 0) {
 676                 syslog(LOG_ERR, "Path %s not found.", first_name);
 677                 free(dname);
 678                 return (-EINVAL);
 679         }
 680 
 681         if ((stk = cstack_new()) == NULL) {
 682                 free(dname);
 683                 syslog(LOG_DEBUG, "cstack_new failed");
 684                 return (-ENOMEM);
 685         }
 686         (void) strlcpy(dir_info.fd_dir_name, first_name, TLM_MAX_PATH_NAME);
 687         (void) memcpy(&dir_info.fd_dir_fh, &ret_fh, sizeof (fs_fhandle_t));
 688         p_dir_info = dup_dir_info(&dir_info);
 689 
 690         /*
 691          * Push the first name onto the stack so that we can pop it back
 692          * off as part of the normal cycle
 693          */
 694         if (cstack_push(stk, p_dir_info, 0)) {
 695                 free(dname);
 696                 free(p_dir_info);
 697                 cstack_delete(stk);
 698                 syslog(LOG_DEBUG, "cstack_push failed");
 699                 return (-ENOMEM);
 700         }
 701 
 702         (void) memset(&tlm_acls, 0, sizeof (tlm_acls));
 703         /*
 704          * Did NDMP create a checkpoint?
 705          */
 706         if (NLP_ISCHKPNTED(nlp) || fs_is_rdonly(bk_path)) {
 707                 tlm_acls.acl_checkpointed = FALSE;
 708         } else {
 709                 /* Use the checkpoint created by NDMP */
 710                 tlm_acls.acl_checkpointed = TRUE;
 711         }
 712 
 713         /*
 714          * This is level-backup.  It never resets the archive bit.
 715          */
 716         tlm_acls.acl_clear_archive = FALSE;
 717 
 718         syslog(LOG_DEBUG, "acls.chkpnt: %c acls.clear_arcbit: %c",
 719             NDMP_YORN(tlm_acls.acl_checkpointed),
 720             NDMP_YORN(tlm_acls.acl_clear_archive));
 721 
 722         while (commands->tcs_reader == TLM_BACKUP_RUN &&
 723             local_commands->tc_reader == TLM_BACKUP_RUN &&
 724             cstack_pop(stk, (void **)&p_dir_info, 0) == 0) {
 725 
 726                 if (NLP_ISCHKPNTED(nlp))
 727                         (void) strlcpy(np->nr_unchkp_nm,
 728                             p_dir_info->fd_dir_name, TLM_MAX_PATH_NAME);
 729                 else
 730                         (void) tlm_remove_checkpoint(p_dir_info->fd_dir_name,
 731                             np->nr_unchkp_nm);
 732 
 733                 (void) backup_dir(np->nr_unchkp_nm, &tlm_acls, local_commands,
 734                     job_stats, &bks);
 735 
 736 
 737                 while (commands->tcs_reader == TLM_BACKUP_RUN &&
 738                     local_commands->tc_reader == TLM_BACKUP_RUN) {
 739 
 740                         dname_size = TLM_MAX_PATH_NAME - 1;
 741 
 742                         syslog(LOG_DEBUG,
 743                             "dir_name: %s", p_dir_info->fd_dir_name);
 744 
 745                         (void) memset(&ret_fh, 0, sizeof (ret_fh));
 746                         erc = fs_readdir(&p_dir_info->fd_dir_fh,
 747                             p_dir_info->fd_dir_name, &dpos,
 748                             dname, &dname_size, &ret_fh, &ret_attr);
 749                         if (erc == 0) {
 750                                 fileid = ret_fh.fh_fid;
 751                         } else {
 752                                 syslog(LOG_DEBUG,
 753                                     "Filesystem readdir in [%s]",
 754                                     p_dir_info->fd_dir_name);
 755                                 retval = -ENOENT;
 756                                 break;
 757                         }
 758 
 759                         /* an empty name size marks the end of the list */
 760                         if (dname_size == 0)
 761                                 break;
 762                         dname[dname_size] = '\0';
 763 


 764                         /*
 765                          * If name refers to a directory, push its file
 766                          *   handle onto the stack  (skip "." and "..").
 767                          */
 768                         if (rootfs_dot_or_dotdot(dname)) {
 769                                 fileid = 0;
 770                                 continue;
 771                         }
 772 
 773                         /*
 774                          * Skip the:
 775                          * non-dir entries which should not be backed up
 776                          * Or
 777                          * dir-type entries which have have nothing under
 778                          * their hierarchy to be backed up.
 779                          */
 780                         if (!dbm_getone(nlp->nlp_bkmap, (u_longlong_t)fileid)) {
 781                                 syslog(LOG_DEBUG, "Skipping %s/%s",
 782                                     p_dir_info->fd_dir_name, dname);
 783                                 fileid = 0;
 784                                 continue;
 785                         }
 786 
 787                         if (tlm_is_excluded(np->nr_unchkp_nm, dname,
 788                             np->nr_excls)) {
 789                                 fileid = 0;
 790                                 continue;
 791                         }
 792                         if (S_ISDIR(ret_attr.st_mode)) {
 793                                 /*
 794                                  * only directories get pushed onto this stack,
 795                                  * so we do not have to test for regular files.
 796                                  */
 797                                 t_dir_info = tlm_new_dir_info(&ret_fh,
 798                                     p_dir_info->fd_dir_name, dname);
 799                                 if (t_dir_info == NULL) {
 800                                         syslog(LOG_DEBUG,
 801                                             "While backing up [%s][%s]",
 802                                             p_dir_info->fd_dir_name, dname);
 803                                 } else if (cstack_push(stk, t_dir_info,
 804                                     0) != 0) {
 805                                         syslog(LOG_DEBUG,
 806                                             "No enough memory stack_push");
 807                                         retval = -ENOMEM;
 808                                         break;
 809                                 }
 810                         } else if (S_ISREG(ret_attr.st_mode) ||
 811                             S_ISLNK(ret_attr.st_mode)) {
 812 
 813                                 fsize = backup_file(np->nr_unchkp_nm, dname,
 814                                     &tlm_acls, commands, local_commands,
 815                                     job_stats, &bks);
 816 
 817                                 if (fsize >= 0) {
 818                                         job_stats->js_files_so_far++;
 819                                         job_stats->js_bytes_total += fsize;
 820                                 } else
 821                                         job_stats->js_errors++;
 822                                 fileid = 0;
 823                         }
 824                 }
 825                 fileid = 0;


 875         }
 876         return (rv);
 877 }
 878 
 879 
 880 /*
 881  * ndmp_backup_reader
 882  *
 883  * Backup reader thread which uses backup_work to read and TAR
 884  * the files/dirs to be backed up (V2 only)
 885  */
 886 static int
 887 ndmp_backup_reader(tlm_commands_t *commands, ndmp_lbr_params_t *nlp,
 888     char *job_name)
 889 {
 890         int retval;
 891         ndmp_run_args_t np;
 892         tlm_job_stats_t *job_stats;
 893         tlm_cmd_t *local_commands;
 894 
 895         syslog(LOG_DEBUG, "bk_path: \"%s\"", nlp->nlp_backup_path);
 896 
 897         local_commands = commands->tcs_command;
 898         (void) memset(&np, 0, sizeof (np));
 899         if (!malloc_paths(&np))
 900                 return (-1);
 901         local_commands->tc_ref++;
 902         commands->tcs_reader_count++;
 903 
 904         job_stats = tlm_ref_job_stats(job_name);
 905 
 906         retval = backup_work(nlp->nlp_backup_path, job_stats, &np,
 907             commands, nlp);
 908         write_tar_eof(local_commands);
 909 
 910         commands->tcs_reader_count--;
 911         local_commands->tc_writer = TLM_STOP;
 912         tlm_release_reader_writer_ipc(local_commands);
 913         tlm_un_ref_job_stats(job_name);
 914 
 915         free_paths(&np);


 919 
 920 
 921 /*
 922  * ndmp_tar_writer
 923  *
 924  * The backup writer thread that writes the TAR records to the
 925  * tape media (V2 only)
 926  */
 927 int
 928 ndmp_tar_writer(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
 929     tlm_commands_t *cmds)
 930 {
 931         int bidx, nw;
 932         int err;
 933         tlm_buffer_t *buf;
 934         tlm_buffers_t *bufs;
 935         tlm_cmd_t *lcmd;        /* Local command */
 936 
 937         err = 0;
 938         if (session == NULL) {

 939                 err = -1;
 940         } else if (mod_params == NULL) {

 941                 err = -1;
 942         } else if (cmds == NULL) {

 943                 err = -1;
 944         }
 945 
 946         if (err != 0)
 947                 return (err);
 948 
 949         lcmd = cmds->tcs_command;
 950         bufs = lcmd->tc_buffers;
 951 
 952         lcmd->tc_ref++;
 953         cmds->tcs_writer_count++;
 954 
 955         nw = 0;
 956         buf = tlm_buffer_out_buf(bufs, &bidx);
 957         while (cmds->tcs_writer != (int)TLM_ABORT &&
 958             lcmd->tc_writer != (int)TLM_ABORT) {
 959                 if (buf->tb_full) {


 960                         if (MOD_WRITE(mod_params, buf->tb_buffer_data,
 961                             buf->tb_buffer_size) != 0) {
 962                                 syslog(LOG_DEBUG,
 963                                     "Writing buffer %d, pos: %lld",
 964                                     bidx, session->ns_mover.md_position);
 965                                 err = -1;
 966                                 break;
 967                         }
 968 
 969                         tlm_buffer_mark_empty(buf);
 970                         (void) tlm_buffer_advance_out_idx(bufs);
 971                         buf = tlm_buffer_out_buf(bufs, &bidx);
 972                         tlm_buffer_release_out_buf(bufs);
 973                         nw++;
 974                 } else {
 975                         if (lcmd->tc_writer != TLM_BACKUP_RUN) {
 976                                 /* No more data is comming; time to exit. */


 977                                 break;
 978                         } else {

 979                                 tlm_buffer_in_buf_timed_wait(bufs, 100);
 980                         }
 981                 }
 982         }
 983 












 984         cmds->tcs_writer_count--;
 985         lcmd->tc_reader = TLM_STOP;
 986         lcmd->tc_ref--;
 987 
 988         return (err);
 989 }
 990 
 991 
 992 /*
 993  * read_one_buf
 994  *
 995  * Read one buffer from the tape
 996  */
 997 static int
 998 read_one_buf(ndmpd_module_params_t *mod_params, tlm_buffers_t *bufs,
 999     tlm_buffer_t *buf)
1000 {
1001         int rv;
1002 
1003         if ((rv = MOD_READ(mod_params, buf->tb_buffer_data,


1025 ndmp_tar_reader(ndmp_tar_reader_arg_t *argp)
1026 {
1027         int bidx;
1028         int err;
1029         tlm_buffer_t *buf;
1030         tlm_buffers_t *bufs;
1031         tlm_cmd_t *lcmd;        /* Local command */
1032         ndmpd_session_t *session;
1033         ndmpd_module_params_t *mod_params;
1034         tlm_commands_t *cmds;
1035 
1036         if (!argp)
1037                 return (-1);
1038 
1039         session = argp->tr_session;
1040         mod_params = argp->tr_mod_params;
1041         cmds = argp->tr_cmds;
1042 
1043         err = 0;
1044         if (session == NULL) {

1045                 err = -1;
1046         } else if (cmds == NULL) {

1047                 err = -1;
1048         }
1049 
1050         if (err != 0) {
1051                 tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER);
1052                 return (err);
1053         }
1054 
1055         lcmd = cmds->tcs_command;
1056         bufs = lcmd->tc_buffers;
1057 
1058         lcmd->tc_ref++;
1059         cmds->tcs_reader_count++;
1060 
1061         /*
1062          * Synchronize with our parent thread.
1063          */
1064         tlm_cmd_signal(cmds->tcs_command, TLM_TAR_READER);
1065 
1066         buf = tlm_buffer_in_buf(bufs, &bidx);
1067         while (cmds->tcs_reader == TLM_RESTORE_RUN &&
1068             lcmd->tc_reader == TLM_RESTORE_RUN) {
1069 
1070                 if (buf->tb_full) {

1071                         /*
1072                          * The buffer is still full, wait for the consumer
1073                          * thread to use it.
1074                          */
1075                         tlm_buffer_out_buf_timed_wait(bufs, 100);
1076                         buf = tlm_buffer_in_buf(bufs, NULL);
1077                 } else {


1078                         err = read_one_buf(mod_params, bufs, buf);
1079                         if (err < 0) {
1080                                 syslog(LOG_DEBUG,
1081                                     "Reading buffer %d, pos: %lld",
1082                                     bidx, session->ns_mover.md_position);
1083 
1084                                 /* Force the writer to stop. */
1085                                 buf->tb_eot = buf->tb_eof = TRUE;
1086                                 break;
1087                         } else if (err == 1) {
1088                                 syslog(LOG_DEBUG,
1089                                     "operation aborted or session terminated");
1090                                 err = 0;
1091                                 break;
1092                         }
1093 
1094                         buf = tlm_buffer_in_buf(bufs, &bidx);
1095                         tlm_buffer_release_in_buf(bufs);
1096                 }
1097         }
1098 
1099         /*
1100          * If the consumer is waiting for us, wake it up so that it detects
1101          * we're quiting.
1102          */
1103         lcmd->tc_writer = TLM_STOP;
1104         tlm_buffer_release_in_buf(bufs);
1105         (void) usleep(1000);
1106 
1107         /*
1108          * Clean up.


1111         lcmd->tc_ref--;
1112         return (err);
1113 }
1114 
1115 
1116 /*
1117  * ndmpd_tar_backup
1118  *
1119  * Check must have been done that backup work directory exists, before
1120  * calling this function.
1121  */
1122 static int
1123 ndmpd_tar_backup(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
1124     ndmp_lbr_params_t *nlp)
1125 {
1126         char jname[TLM_MAX_BACKUP_JOB_NAME];
1127         int err;
1128         tlm_commands_t *cmds;
1129 
1130         if (mod_params->mp_operation != NDMP_DATA_OP_BACKUP) {
1131                 syslog(LOG_DEBUG,
1132                     "mod_params->mp_operation != NDMP_DATA_OP_BACKUP");
1133                 err = -1;
1134         } else {
1135                 if (ndmpd_mark_inodes_v2(session, nlp) != 0)
1136                         err = -1;
1137                 else if (ndmp_get_bk_dir_ino(nlp))
1138                         err = -1;
1139                 else
1140                         err = 0;
1141         }
1142 
1143         if (err != 0)
1144                 return (err);
1145 
1146         if (ndmp_new_job_name(jname, sizeof (jname)) <= 0) {

1147                 return (-1);
1148         }
1149         if (backup_create_structs(session, jname) < 0) {
1150                 return (-1);
1151         }
1152         nlp->nlp_jstat->js_start_ltime = time(NULL);
1153         nlp->nlp_jstat->js_start_time = nlp->nlp_jstat->js_start_ltime;
1154         nlp->nlp_jstat->js_chkpnt_time = nlp->nlp_cdate;
1155 
1156         if (!session->ns_data.dd_abort) {
1157 
1158                 cmds = &nlp->nlp_cmds;
1159                 cmds->tcs_reader = cmds->tcs_writer = TLM_BACKUP_RUN;
1160                 cmds->tcs_command->tc_reader = TLM_BACKUP_RUN;
1161                 cmds->tcs_command->tc_writer = TLM_BACKUP_RUN;
1162 
1163                 if (ndmp_write_utf8magic(cmds->tcs_command) < 0) {
1164                         backup_release_structs(session);
1165                         return (-1);
1166                 }
1167 
1168                 syslog(LOG_DEBUG, "Backing up \"%s\" started.",
1169                     nlp->nlp_backup_path);
1170 
1171                 err = ndmp_backup_reader(cmds, nlp, jname);
1172                 if (err != 0) {
1173                         backup_release_structs(session);
1174                         syslog(LOG_DEBUG, "Launch ndmp_backup_reader: %s",
1175                             strerror(err));
1176                         return (-1);
1177                 }
1178 
1179                 /* Act as the writer thread. */
1180                 err = ndmp_tar_writer(session, mod_params, cmds);
1181 
1182                 nlp->nlp_jstat->js_stop_time = time(NULL);
1183 
1184                 syslog(LOG_DEBUG,
1185                     "Runtime [%s] %lu bytes (%llu): %d seconds",
1186                     nlp->nlp_backup_path, session->ns_mover.md_data_written,
1187                     session->ns_mover.md_data_written,
1188                     nlp->nlp_jstat->js_stop_time -
1189                     nlp->nlp_jstat->js_start_ltime);
1190                 MOD_LOG(mod_params,
1191                     "Runtime [%s] %lu bytes (%lu): %d seconds",
1192                     nlp->nlp_backup_path, session->ns_mover.md_data_written,
1193                     session->ns_mover.md_data_written,
1194                     nlp->nlp_jstat->js_stop_time -
1195                     nlp->nlp_jstat->js_start_ltime);
1196 
1197                 if (session->ns_data.dd_abort)
1198                         err = -1;
1199 
1200                 syslog(LOG_DEBUG, "Backing up \"%s\" finished. (%d)",
1201                     nlp->nlp_backup_path, err);
1202         } else {
1203                 nlp->nlp_jstat->js_stop_time = time(NULL);
1204                 syslog(LOG_DEBUG, "Backing up \"%s\" aborted.",
1205                     nlp->nlp_backup_path);
1206                 err = 0;
1207         }
1208 
1209         backup_release_structs(session);
1210         return (err);
1211 }
1212 
1213 
1214 /*
1215  * ndmpd_tar_restore
1216  *
1217  * Restore function that launches TAR reader thread to read from the
1218  * tape and writes the extracted files/dirs to the filesystem
1219  */
1220 static int
1221 ndmpd_tar_restore(ndmpd_session_t *session, ndmpd_module_params_t *mod_params,
1222     ndmp_lbr_params_t *nlp)
1223 {
1224         char jname[TLM_MAX_BACKUP_JOB_NAME];
1225         char *rspath;
1226         int err;
1227         tlm_commands_t *cmds;
1228         ndmp_tar_reader_arg_t arg;
1229         tlm_backup_restore_arg_t tlm_arg;
1230         ndmp_name *ent;
1231         pthread_t rdtp, wrtp;
1232         int i;
1233 
1234         if (mod_params->mp_operation != NDMP_DATA_OP_RECOVER) {


1235                 return (-1);
1236         }
1237 
1238         if (nlp->nlp_restore_path[0] != '\0')
1239                 rspath = nlp->nlp_restore_path;
1240         else if (nlp->nlp_restore_bk_path[0] != '\0')
1241                 rspath = nlp->nlp_restore_bk_path;
1242         else
1243                 rspath = "";
1244 
1245         if (ndmp_new_job_name(jname, sizeof (jname)) <= 0) {

1246                 return (-1);
1247         }
1248         if (restore_create_structs(session, jname) < 0) {
1249                 return (-1);
1250         }
1251 
1252         nlp->nlp_jstat->js_start_ltime = time(NULL);
1253         nlp->nlp_jstat->js_start_time = time(NULL);
1254 
1255         if (!session->ns_data.dd_abort) {
1256                 cmds = &nlp->nlp_cmds;
1257                 cmds->tcs_reader = cmds->tcs_writer = TLM_RESTORE_RUN;
1258                 cmds->tcs_command->tc_reader = TLM_RESTORE_RUN;
1259                 cmds->tcs_command->tc_writer = TLM_RESTORE_RUN;
1260 
1261                 syslog(LOG_DEBUG, "Restoring to \"%s\" started.", rspath);
1262                 syslog(LOG_DEBUG, "Restoring from %s tape(s).",
1263                     ndmp_data_get_mover_mode(session));
1264 
1265                 arg.tr_session = session;
1266                 arg.tr_mod_params = mod_params;
1267                 arg.tr_cmds = cmds;
1268 
1269                 err = pthread_create(&rdtp, NULL, (funct_t)ndmp_tar_reader,
1270                     (void *)&arg);
1271                 if (err == 0) {
1272                         tlm_cmd_wait(cmds->tcs_command, TLM_TAR_READER);
1273                 } else {
1274                         syslog(LOG_DEBUG, "Launch ndmp_tar_reader: %m");
1275                         return (-1);
1276                 }
1277 
1278                 if (!ndmp_check_utf8magic(cmds->tcs_command)) {
1279                         syslog(LOG_DEBUG, "UTF8Magic not found!");
1280                 } else {
1281                         syslog(LOG_DEBUG, "UTF8Magic found");
1282                 }
1283 
1284                 (void) memset(&tlm_arg, 0, sizeof (tlm_backup_restore_arg_t));
1285                 (void) pthread_barrier_init(&tlm_arg.ba_barrier, 0, 2);
1286 
1287                 /*
1288                  * Set up restore parameters
1289                  */
1290                 tlm_arg.ba_commands = cmds;
1291                 tlm_arg.ba_cmd = cmds->tcs_command;
1292                 tlm_arg.ba_job = nlp->nlp_jstat->js_job_name;
1293                 tlm_arg.ba_dir = nlp->nlp_restore_path;
1294                 for (i = 0; i < nlp->nlp_nfiles; i++) {
1295                         ent = (ndmp_name *)MOD_GETNAME(mod_params, i);
1296                         tlm_arg.ba_sels[i] = strdup(ent->name);
1297                 }
1298                 tlm_arg.ba_count = i;
1299 

1300                 if (tm_tar_ops.tm_getfile != NULL) {
1301                         err = pthread_create(&wrtp, NULL,
1302                             (funct_t)tm_tar_ops.tm_getfile, (void *)&tlm_arg);
1303                 } else {
1304                         (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1305                         syslog(LOG_DEBUG,
1306                             "Thread create tm_getfile: ops NULL");
1307                         return (-1);
1308                 }
1309                 if (err == 0) {
1310                         (void) pthread_barrier_wait(&tlm_arg.ba_barrier);
1311                 } else {
1312                         (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1313                         syslog(LOG_DEBUG, "thread create tm_getfile: %m");
1314                         return (-1);
1315                 }
1316 
1317                 (void) pthread_join(rdtp, NULL);
1318                 (void) pthread_join(wrtp, NULL);
1319                 (void) pthread_barrier_destroy(&tlm_arg.ba_barrier);
1320 
1321                 nlp->nlp_jstat->js_stop_time = time(NULL);
1322 
1323                 /* Send the list of un-recovered files/dirs to the client.  */
1324                 (void) send_unrecovered_list(mod_params, nlp);
1325 
1326                 ndmp_stop_local_reader(session, cmds);
1327                 ndmp_wait_for_reader(cmds);
1328                 ndmp_stop_remote_reader(session);
1329                 syslog(LOG_DEBUG, "Restoring to \"%s\" finished. (%d)",
1330                     rspath, err);
1331         } else {
1332                 nlp->nlp_jstat->js_stop_time = time(NULL);
1333 
1334                 /* nothing restored. */
1335                 (void) send_unrecovered_list(mod_params, nlp);
1336                 syslog(LOG_DEBUG, "Restoring to \"%s\" aborted.",
1337                     rspath);
1338                 err = -1;
1339         }
1340 
1341         NDMP_FREE(nlp->nlp_restore_path);
1342         backup_release_structs(session);
1343 
1344         return (err);
1345 }
1346 
1347 
1348 /*
1349  * prefixdir
1350  *
1351  * Extract the path for a given full path entry
1352  */
1353 static char *
1354 prefixdir(char *dir, char *suffix)
1355 {
1356         static char tmp[TLM_MAX_PATH_NAME];


1441  * Correct the entries in the restore list by appending the appropriate
1442  * path to them
1443  */
1444 static int
1445 correct_ents(ndmpd_module_params_t *params, int n, char *bkpath)
1446 {
1447         char *cp, *pathname;
1448         int i, len, rv;
1449         ndmp_name *ent;
1450 
1451         if ((pathname = ndmp_malloc(TLM_MAX_PATH_NAME)) == NULL) {
1452                 MOD_LOG(params, "Error: insufficient memory.\n");
1453                 return (-1);
1454         }
1455 
1456         rv = 0;
1457         /* Append the backup path to all the "ent[].name"s. */
1458         for (i = 0; i < n; i++) {
1459                 ent = (ndmp_name *)MOD_GETNAME(params, i);
1460 
1461                 syslog(LOG_DEBUG,
1462                     "Old: ent[%d].name: \"%s\"", i, ent->name);
1463                 syslog(LOG_DEBUG,
1464                     "Old: ent[%d].dest: \"%s\"", i, ent->dest);
1465 
1466                 /* remove trailing slash */
1467                 len = strlen(ent->name);
1468                 if (ent->name[len - 1] == '/')
1469                         ent->name[len - 1] = '\0';
1470 
1471                 if (!tlm_cat_path(pathname, bkpath, ent->name)) {
1472                         MOD_LOG(params, "Error: path too long.\n");
1473                         rv = -1;
1474                         break;
1475                 }
1476 
1477                 /* Make a copy of the new string and save it in ent->name. */
1478                 cp = strdup(pathname);
1479                 if (cp == NULL) {
1480                         MOD_LOG(params, "Error: insufficient memory.\n");
1481                         rv = -1;
1482                         break;
1483                 }
1484                 free(ent->name);
1485                 ent->name = cp;
1486 
1487                 syslog(LOG_DEBUG,
1488                     "New: ent[%d].name: \"%s\"", i, ent->name);
1489         }
1490 
1491         free(pathname);
1492         return (rv);
1493 }
1494 
1495 
1496 /*
1497  * check_restore_paths
1498  *
1499  * Go through the restore list and check the validity of the
1500  * restore path.
1501  */
1502 static int
1503 check_restore_paths(ndmpd_module_params_t *params, int n, char *rspath)
1504 {
1505         int i, rv;
1506         ndmp_name *ent;
1507 
1508         rv = 0;
1509         if (rspath != NULL && *rspath != '\0') {
1510                 syslog(LOG_DEBUG, "rspath: \"%s\"", rspath);
1511                 if (!fs_volexist(rspath)) {
1512                         MOD_LOG(params,
1513                             "Error: Invalid volume name for restore.");
1514                         rv = -1;
1515                 }
1516         } else {
1517                 for (i = 0; i < n; i++) {
1518                         ent = (ndmp_name *)MOD_GETNAME(params, i);
1519                         syslog(LOG_DEBUG,
1520                             "ent[%d].name: \"%s\"", i, ent->name);
1521 
1522                         if (!fs_volexist(ent->name)) {
1523                                 MOD_LOG(params,
1524                                     "Error: Invalid volume name for restore.",
1525                                     ent->name);
1526                                 rv = -1;
1527                                 break;
1528                         }
1529                 }
1530         }
1531 
1532         return (rv);
1533 }
1534 
1535 
1536 /*
1537  * check_backup_dir_validity
1538  *
1539  * Check if the backup directory is valid. Make sure it exists and


1576     ndmpd_module_params_t *params)
1577 {
1578         char *cp;
1579         int rv;
1580         ndmp_lbr_params_t *nlp;
1581 
1582         /* Extract directory to be backed up from env variables */
1583         if ((nlp = ndmp_get_nlp(session)) == NULL) {
1584                 MOD_LOG(params, "Error: Internal error: nlp == NULL.\n");
1585                 return (NDMP_ILLEGAL_ARGS_ERR);
1586         }
1587         if ((nlp->nlp_backup_path = get_backup_path_v2(params)) == NULL)
1588                 return (NDMP_FILE_NOT_FOUND_ERR);
1589 
1590         if ((rv = check_backup_dir_validity(params,
1591             nlp->nlp_backup_path)) != NDMP_NO_ERR)
1592                 return (rv);
1593 
1594         /* Should the st_ctime be ignored when backing up? */
1595         if (ndmp_ignore_ctime) {
1596                 syslog(LOG_DEBUG, "ignoring st_ctime");
1597                 NLP_SET(nlp, NLPF_IGNCTIME);
1598         } else
1599                 NLP_UNSET(nlp, NLPF_IGNCTIME);
1600 
1601         /* Should the st_lmtime be ignored when backing up? */
1602         if (ndmp_include_lmtime) {
1603                 syslog(LOG_DEBUG, "including st_lmtime");
1604                 NLP_SET(nlp, NLPF_INCLMTIME);
1605         } else
1606                 NLP_UNSET(nlp, NLPF_INCLMTIME);
1607 
1608         syslog(LOG_DEBUG, "flags %x", nlp->nlp_flags);
1609 
1610         /* Is backup history requested? */
1611         cp = MOD_GETENV(params, "HIST");
1612         if (cp == NULL) {
1613                 syslog(LOG_DEBUG, "env(HIST) not specified");
1614                 NLP_UNSET(nlp, NLPF_FH);
1615         } else {
1616                 syslog(LOG_DEBUG, "env(HIST): \"%s\"", cp);
1617 
1618                 if (strchr("t_ty_y", *cp))
1619                         NLP_SET(nlp, NLPF_FH);
1620                 else
1621                         NLP_UNSET(nlp, NLPF_FH);
1622         }
1623 
1624         nlp->nlp_clevel = 0;
1625         /* Is it an incremental backup? */
1626         cp = MOD_GETENV(params, "LEVEL");
1627         if (cp == NULL) {
1628                 syslog(LOG_DEBUG,
1629                     "env(LEVEL) not specified, default to 0");
1630         } else if (*cp < '0' || *cp > '9' || *(cp+1) != '\0') {
1631                 syslog(LOG_DEBUG, "Invalid backup level '%s'", cp);
1632                 return (NDMP_ILLEGAL_ARGS_ERR);
1633         } else
1634                 nlp->nlp_clevel = *cp - '0';
1635 
1636         /* Extract last backup time from the dumpdates file */
1637         nlp->nlp_llevel = nlp->nlp_clevel;
1638         nlp->nlp_ldate = 0;
1639         if (ndmpd_get_dumptime(nlp->nlp_backup_path, &nlp->nlp_llevel,
1640             &nlp->nlp_ldate) < 0) {
1641                 MOD_LOG(params, "Error: getting dumpdate for %s level %d\n",
1642                     nlp->nlp_backup_path, nlp->nlp_clevel);
1643                 return (NDMP_NO_MEM_ERR);
1644         }
1645 
1646         syslog(LOG_DEBUG,
1647             "Date of this level %d on \"%s\": %s",
1648             nlp->nlp_clevel, nlp->nlp_backup_path, cctime(&nlp->nlp_cdate));
1649         syslog(LOG_DEBUG,
1650             "Date of last level %d on \"%s\": %s",
1651             nlp->nlp_llevel, nlp->nlp_backup_path, cctime(&nlp->nlp_ldate));
1652 
1653         /* Should the dumpdate file be updated? */
1654         cp = MOD_GETENV(params, "UPDATE");
1655         if (cp == NULL) {
1656                 syslog(LOG_DEBUG,
1657                     "env(UPDATE) not specified, default to TRUE");
1658                 NLP_SET(nlp, NLPF_UPDATE);
1659         } else {
1660                 syslog(LOG_DEBUG, "env(UPDATE): \"%s\"", cp);
1661                 if (strchr("t_ty_y", *cp) != NULL)
1662                         NLP_SET(nlp, NLPF_UPDATE);
1663                 else
1664                         NLP_UNSET(nlp, NLPF_UPDATE);
1665         }
1666 
1667         return (NDMP_NO_ERR);
1668 }
1669 
1670 
1671 
1672 /*
1673  * log_bk_params_v2
1674  *
1675  * Dump the value of the parameters in the log file for debugging.
1676  */
1677 void
1678 log_bk_params_v2(ndmpd_session_t *session, ndmpd_module_params_t *params,
1679     ndmp_lbr_params_t *nlp)
1680 {


1707 same_path(char *s, char *t)
1708 {
1709         boolean_t rv;
1710         int slen, tlen;
1711 
1712         rv = FALSE;
1713         slen = strlen(s);
1714         tlen = strlen(t);
1715         if (slen == tlen && strcmp(s, t) == 0) {
1716                 rv = TRUE;
1717         } else {
1718                 if (slen == tlen - 1) {
1719                         if (strncmp(s, t, slen) == 0 && t[tlen - 1] == '/')
1720                                 rv = TRUE;
1721                 } else if (tlen == slen -1) {
1722                         if (strncmp(s, t, tlen) == 0 && s[slen - 1] == '/')
1723                                 rv = TRUE;
1724                 }
1725         }
1726 
1727         syslog(LOG_DEBUG, "rv: %d", rv);
1728         return (rv);
1729 }
1730 
1731 
1732 /*
1733  * ndmp_restore_extract_params
1734  *
1735  * Go through the restore parameters and check them and extract them
1736  * by setting NLP flags and other values.
1737  *
1738  * Parameters:
1739  *
1740  * Returns:
1741  *   0: on success
1742  *  -1: otherwise
1743  */
1744 int
1745 ndmp_restore_extract_params(ndmpd_session_t *session,
1746     ndmpd_module_params_t *params)
1747 {
1748         char *bkpath, *rspath;
1749         ndmp_lbr_params_t *nlp;
1750 
1751         if ((nlp = ndmp_get_nlp(session)) == NULL) {

1752                 return (-1);
1753         }
1754 
1755         /* Extract directory from where the backup was made. */
1756         if ((bkpath = get_backup_path_v2(params)) == NULL)
1757                 return (NDMP_ILLEGAL_ARGS_ERR);
1758 
1759         nlp->nlp_restore_bk_path = bkpath;
1760 
1761         /* The number of the selections. */
1762         if ((nlp->nlp_nfiles = get_nfiles(session, params)) == 0)
1763                 return (NDMP_ILLEGAL_ARGS_ERR);
1764 
1765         syslog(LOG_DEBUG, "nfiles: %d", nlp->nlp_nfiles);
1766 
1767         if ((rspath = get_restore_dest(params)) == NULL)
1768                 return (NDMP_ILLEGAL_ARGS_ERR);
1769 
1770         if (fs_is_rdonly(rspath)) {
1771                 MOD_LOG(params,
1772                     "Error: Can't restore to a read-only volume: \"%s\"\n",
1773                     rspath);
1774                 return (NDMP_ILLEGAL_ARGS_ERR);
1775         }
1776         if (fs_is_chkpntvol(rspath)) {
1777                 MOD_LOG(params,
1778                     "Error: Can't restore to a checkpoint: \"%s\"\n", rspath);
1779                 return (NDMP_ILLEGAL_ARGS_ERR);
1780         }
1781 
1782         if (same_path(bkpath, rspath))
1783                 rspath = "";
1784 
1785         if ((nlp->nlp_restore_path = strdup(rspath)) == NULL)


1812  */
1813 int
1814 ndmpd_tar_backup_starter(void *arg)
1815 {
1816         ndmpd_module_params_t *mod_params = arg;
1817         int err;
1818         ndmpd_session_t *session;
1819         ndmp_lbr_params_t *nlp;
1820 
1821         session = (ndmpd_session_t *)(mod_params->mp_daemon_cookie);
1822         *(mod_params->mp_module_cookie) = nlp = ndmp_get_nlp(session);
1823         ndmp_session_ref(session);
1824 
1825         err = 0;
1826         if (fs_is_chkpntvol(nlp->nlp_backup_path) ||
1827             fs_is_rdonly(nlp->nlp_backup_path) ||
1828             !fs_is_chkpnt_enabled(nlp->nlp_backup_path))
1829                 NLP_SET(nlp, NLPF_CHKPNTED_PATH);
1830         else {
1831                 NLP_UNSET(nlp, NLPF_CHKPNTED_PATH);
1832                 if (backup_dataset_create(nlp) < 0) {

1833                         MOD_LOG(mod_params,
1834                             "Error: creating checkpoint on %s\n",
1835                             nlp->nlp_backup_path);
1836                         /* -1 causes halt reason to become internal error. */
1837                         err = -1;
1838                 }
1839         }
1840 
1841         syslog(LOG_DEBUG, "NLPF_CHKPNTED_PATH: %c",
1842             NDMP_YORN(NLP_ISCHKPNTED(nlp)));
1843         syslog(LOG_DEBUG, "err: %d, update %c",
1844             err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1845 
1846         if (err == 0) {
1847                 err = ndmp_get_cur_bk_time(nlp, &nlp->nlp_cdate);

1848                 if (err != 0) {
1849                         syslog(LOG_DEBUG, "err %d", err);
1850                 } else {
1851                         log_bk_params_v2(session, mod_params, nlp);
1852                         err = ndmpd_tar_backup(session, mod_params, nlp);
1853                 }
1854         }
1855 
1856         if (nlp->nlp_bkmap >= 0) {
1857                 (void) dbm_free(nlp->nlp_bkmap);
1858                 nlp->nlp_bkmap = -1;
1859         }
1860 
1861         if (!NLP_ISCHKPNTED(nlp))
1862                 (void) backup_dataset_destroy(nlp);

1863 
1864         syslog(LOG_DEBUG, "err %d, update %c",
1865             err, NDMP_YORN(NLP_SHOULD_UPDATE(nlp)));
1866 
1867         if (err == 0 && NLP_SHOULD_UPDATE(nlp)) {
1868                 if (ndmpd_put_dumptime(nlp->nlp_backup_path, nlp->nlp_clevel,
1869                     nlp->nlp_cdate) < 0) {
1870                         err = EPERM;
1871                         MOD_LOG(mod_params,
1872                             "Error: updating the dumpdates file on %s\n",
1873                             nlp->nlp_backup_path);
1874                 }
1875         }
1876 
1877         MOD_DONE(mod_params, err);
1878 
1879         /* nlp_params is allocated in start_backup() */
1880         NDMP_FREE(nlp->nlp_params);
1881 
1882         NS_DEC(nbk);
1883         ndmp_session_unref(session);
1884         return (err);