1 /*
   2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
   3  * Use is subject to license terms.
   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 #include <sys/stat.h>
  40 #include <sys/types.h>
  41 #include <cstack.h>
  42 #include <ctype.h>
  43 #include <dirent.h>
  44 #include <errno.h>
  45 #include "ndmpd.h"
  46 #include <bitmap.h>
  47 #include <traverse.h>
  48 #include <limits.h>
  49 #include <stdio.h>
  50 #include <stdlib.h>
  51 #include <string.h>
  52 #include <time.h>
  53 #include "tlm_buffers.h"
  54 
  55 
  56 /*
  57  * Parameter passed to traverse for marking inodes
  58  * when traversing backup hierarchy in V2.  It
  59  * includes:
  60  *    mp_bmd: the bitmap describptor.
  61  *    mp_ddate: backup date.
  62  *    mp_session: pointer to the session structure.
  63  *    mp_nlp: pointer to the nlp.
  64  *    mp_tacl: pointer to the acl.
  65  */
  66 typedef struct mark_param {
  67         int mp_bmd;
  68         time_t mp_ddate;
  69         ndmpd_session_t *mp_session;
  70         ndmp_lbr_params_t *mp_nlp;
  71         tlm_acls_t *mp_tacl;
  72 } mark_param_t;
  73 
  74 
  75 /*
  76  * Set this variable to non-zero to print the inodes
  77  * marked after traversing file system.
  78  */
  79 static int ndmpd_print_inodes = 0;
  80 
  81 
  82 /*
  83  * Flag passed to traverse_post.
  84  */
  85 static int ndmpd_mark_flags = 0;
  86 
  87 
  88 /*
  89  * Verbose traversing prints the file/dir path names
  90  * if they are being marked.
  91  */
  92 static int ndmpd_verbose_traverse = 0;
  93 
  94 
  95 /*
  96  * Set this flag to count the number of inodes marked
  97  * after traversing backup hierarchy.
  98  */
  99 static int ndmpd_mark_count_flag = 0;
 100 
 101 
 102 /*
 103  * Set this variable to non-zero value to force traversing
 104  * backup hierarchy for tar format.
 105  */
 106 static int ndmp_tar_force_traverse = 0;
 107 
 108 
 109 /*
 110  * Set this variable to non-zero value to skip processing
 111  * directories both for tar and dump.
 112  */
 113 static int ndmp_skip_traverse = 0;
 114 
 115 
 116 /*
 117  * count_bits_cb
 118  *
 119  * Call back for counting the set bits in the dbitmap.
 120  *
 121  * Parameters:
 122  *   bmd (input) - bitmap descriptor
 123  *   bn (input) - the bit number
 124  *   arg (input) - pointer to the argument
 125  *
 126  * Returns:
 127  *   0: always
 128  */
 129 static int
 130 count_bits_cb(int bmd, u_longlong_t bn, void *arg)
 131 {
 132         if (dbm_getone(bmd, bn)) {
 133                 (*(u_longlong_t *)arg)++;
 134                 if (ndmpd_print_inodes)
 135                         NDMP_LOG(LOG_DEBUG, "%llu", bn);
 136         }
 137 
 138         return (0);
 139 }
 140 
 141 
 142 /*
 143  * count_set_bits
 144  *
 145  * Count bits set in the bitmap.
 146  *
 147  * Parameters:
 148  *   path (input) - the backup path
 149  *   bmd (input) - bitmap descriptor
 150  *
 151  * Returns:
 152  *   void
 153  */
 154 void
 155 count_set_bits(char *path, int bmd)
 156 {
 157         u_longlong_t cnt;
 158 
 159         if (!ndmpd_mark_count_flag)
 160                 return;
 161 
 162         cnt = 0;
 163         (void) dbm_apply_ifset(bmd, count_bits_cb, &cnt);
 164         NDMP_LOG(LOG_DEBUG, "%s %llu inodes marked", path, cnt);
 165 }
 166 
 167 
 168 /*
 169  * traverse
 170  *
 171  * Starts the post-traverse the backup hierarchy.  Checks
 172  * for exceptional cases, like aborting operation and if
 173  * asked, report detailed information after traversing.
 174  *
 175  * Parameters:
 176  *   session (input) - pointer to the session
 177  *   nlp (input) - pointer to the nlp structure
 178  *   ftp (input) - pointer to the traverse parameters
 179  *
 180  * Returns:
 181  *   0: on success
 182  *   != 0: otherwise
 183  */
 184 int
 185 traverse(ndmpd_session_t *session, ndmp_lbr_params_t *nlp,
 186     fs_traverse_t *ftp)
 187 {
 188         int rv;
 189         time_t s, e;
 190 
 191         if (!session || !nlp || !ftp) {
 192                 NDMP_LOG(LOG_DEBUG, "Invalid argument");
 193                 return (-1);
 194         }
 195         NDMP_LOG(LOG_DEBUG, "Processing directories of \"%s\"",
 196             nlp->nlp_backup_path);
 197 
 198         (void) time(&s);
 199         if (traverse_post(ftp) != 0) {
 200                 rv = -1;
 201                 if (!session->ns_data.dd_abort && !NLP_ISSET(nlp,
 202                     NLPF_ABORTED)) {
 203                         NDMP_LOG(LOG_DEBUG,
 204                             "Traversing backup path hierarchy \"%s\"",
 205                             nlp->nlp_backup_path);
 206                 }
 207         } else {
 208                 (void) dbm_setone(nlp->nlp_bkmap, (u_longlong_t)ROOT_INODE);
 209                 rv = 0;
 210                 (void) time(&e);
 211                 NDMP_LOG(LOG_DEBUG,
 212                     "\"%s\" traversed in %u sec", nlp->nlp_backup_path,
 213                     (uint_t)(e-s));
 214 
 215                 count_set_bits(nlp->nlp_backup_path, nlp->nlp_bkmap);
 216         }
 217 
 218         return (rv);
 219 }
 220 
 221 
 222 /*
 223  * mark_cb
 224  *
 225  * The callback function, called by traverse_post to mark bits
 226  * in the bitmap.
 227  *
 228  * Set the bit of the entry if it's been modified (obviously
 229  * should be backed up) plus its parent directory.
 230  *
 231  * If the entry is a directory and is not modified itself,
 232  * but it's marked, then there is something below it that
 233  * is being backed up.  It shows the the path, leads to
 234  * an object that will be backed up. So the path should
 235  * be marked too.
 236  *
 237  * The backup path itself is always marked.
 238  *
 239  * Parameters:
 240  *   arg (input) - pointer to the mark parameter
 241  *   pnp (input) - pointer to the path node
 242  *   enp (input) - pointer to the entry node
 243  *
 244  * Returns:
 245  *   0: as long as traversing should continue
 246  *   != 0: if traversing should stop
 247  */
 248 int
 249 mark_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
 250 {
 251         int bmd;
 252         int rv;
 253         u_longlong_t bl;
 254         time_t ddate;
 255         fs_fhandle_t *pfhp, *efhp;
 256         struct stat64 *pstp, *estp;
 257         mark_param_t *mpp;
 258         ndmp_lbr_params_t *nlp;
 259         tlm_acls_t *tacl;
 260 
 261         rv = 0;
 262         mpp = (mark_param_t *)arg;
 263         tacl = mpp->mp_tacl;
 264         nlp = ndmp_get_nlp(mpp->mp_session);
 265         if (!mpp) {
 266                 NDMP_LOG(LOG_DEBUG, "NULL argument passed");
 267                 rv = -1;
 268         } else if (mpp->mp_session->ns_eof) {
 269                 NDMP_LOG(LOG_INFO, "Connection to the client is closed");
 270                 rv = -1;
 271         } else if (mpp->mp_session->ns_data.dd_abort ||
 272             (nlp && NLP_ISSET(nlp, NLPF_ABORTED))) {
 273                 NDMP_LOG(LOG_INFO, "Processing directories aborted.");
 274                 rv = -1;
 275         }
 276 
 277         if (rv != 0)
 278                 return (rv);
 279 
 280         ddate = mpp->mp_ddate;
 281         bmd = mpp->mp_bmd;
 282         bl = dbm_getlen(bmd);
 283 
 284         pfhp = pnp->tn_fh;
 285         pstp = pnp->tn_st;
 286 
 287         /* sanity check on fh and stat of the path passed */
 288         if (pstp->st_ino > bl) {
 289                 NDMP_LOG(LOG_DEBUG, "Invalid path inode #%u",
 290                     (uint_t)pstp->st_ino);
 291                 return (-1);
 292         }
 293         if (pstp->st_ino != pfhp->fh_fid) {
 294                 NDMP_LOG(LOG_DEBUG, "Path ino mismatch %u %u",
 295                     (uint_t)pstp->st_ino, (uint_t)pfhp->fh_fid);
 296                 return (-1);
 297         }
 298 
 299         /*
 300          * Always mark the backup path inode number.
 301          */
 302         if (!enp->tn_path) {
 303                 (void) dbm_setone(bmd, pstp->st_ino);
 304                 return (0);
 305         }
 306 
 307         efhp = enp->tn_fh;
 308         estp = enp->tn_st;
 309 
 310         /* sanity check on fh and stat of the entry passed */
 311         if (estp->st_ino > bl) {
 312                 NDMP_LOG(LOG_DEBUG, "Invalid entry inode #%u",
 313                     (uint_t)estp->st_ino);
 314                 return (-1);
 315         }
 316         if (estp->st_ino != efhp->fh_fid) {
 317                 NDMP_LOG(LOG_DEBUG, "Entry ino mismatch %u %u", estp->st_ino,
 318                     (uint_t)pfhp->fh_fid);
 319                 return (-1);
 320         }
 321 
 322         /* check the dates and mark the bitmap inode */
 323         if (ddate == 0) {
 324                 /* base backup */
 325                 (void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
 326                 (void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
 327                 if (ndmpd_verbose_traverse) {
 328                         NDMP_LOG(LOG_DEBUG, "Base Backup");
 329                         NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
 330                             pnp->tn_path, enp->tn_path);
 331                 }
 332 
 333         } else if (estp->st_mtime > ddate) {
 334                 (void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
 335                 (void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
 336                 if (ndmpd_verbose_traverse) {
 337                         NDMP_LOG(LOG_DEBUG,
 338                             "m(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
 339                             (uint_t)estp->st_ino, (uint_t)estp->st_mtime,
 340                             (uint_t)ddate);
 341                         NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
 342                             pnp->tn_path, enp->tn_path);
 343                 }
 344         } else if (iscreated(nlp, NULL, tacl, ddate)) {
 345                 (void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
 346                 (void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
 347                 if (ndmpd_verbose_traverse) {
 348                         NDMP_LOG(LOG_DEBUG,
 349                             "cr(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
 350                             (uint_t)estp->st_ino, (uint_t)estp->st_mtime,
 351                             (uint_t)ddate);
 352                         NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
 353                             pnp->tn_path, enp->tn_path);
 354                 }
 355         } else if (estp->st_ctime > ddate) {
 356                 if (!NLP_IGNCTIME(nlp)) {
 357                         (void) dbm_setone(bmd, (u_longlong_t)estp->st_ino);
 358                         (void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
 359                 }
 360                 if (ndmpd_verbose_traverse) {
 361                         if (NLP_IGNCTIME(nlp)) {
 362                                 NDMP_LOG(LOG_DEBUG,
 363                                     "ign c(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
 364                                     (uint_t)estp->st_ino,
 365                                     (uint_t)estp->st_ctime, (uint_t)ddate);
 366                         } else {
 367                                 NDMP_LOG(LOG_DEBUG,
 368                                     "c(%u,%u,%u,%u)", (uint_t)pstp->st_ino,
 369                                     (uint_t)estp->st_ino,
 370                                     (uint_t)estp->st_ctime, (uint_t)ddate);
 371                         }
 372                         NDMP_LOG(LOG_DEBUG, "\"%s/%s\"",
 373                             pnp->tn_path, enp->tn_path);
 374                 }
 375         } else if (S_ISDIR(estp->st_mode) &&
 376             dbm_getone(bmd, (u_longlong_t)estp->st_ino)) {
 377                 (void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
 378                 if (ndmpd_verbose_traverse) {
 379                         NDMP_LOG(LOG_DEBUG, "d(%u,%u)",
 380                             (uint_t)pstp->st_ino, (uint_t)estp->st_ino);
 381                         NDMP_LOG(LOG_DEBUG, "\"%s, %s\"",
 382                             pnp->tn_path, enp->tn_path);
 383                 }
 384         }
 385 
 386         return (0);
 387 }
 388 
 389 
 390 /*
 391  * mark_inodes_v2
 392  *
 393  * Traverse the file system in post-order and mark
 394  * all the modified objects and also directories leading
 395  * to them.
 396  *
 397  * Parameters:
 398  *   session (input) - pointer to the session
 399  *   nlp (input) - pointer to the nlp structure
 400  *   path (input) - the physical path to traverse
 401  *
 402  * Returns:
 403  *   0: on success.
 404  *   != 0: on error.
 405  */
 406 int
 407 mark_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
 408 {
 409         fs_traverse_t ft;
 410         mark_param_t mp;
 411 
 412         if (!session || !nlp || !path || !*path) {
 413                 NDMP_LOG(LOG_DEBUG, "Invalid argument");
 414                 return (-1);
 415         }
 416 
 417         NDMP_LOG(LOG_DEBUG, "path \"%s\"", path);
 418 
 419         mp.mp_bmd = nlp->nlp_bkmap;
 420         mp.mp_ddate = nlp->nlp_ldate;
 421         mp.mp_session = session;
 422         mp.mp_nlp = nlp;
 423 
 424         ft.ft_path = path;
 425         ft.ft_lpath = nlp->nlp_backup_path;
 426         ft.ft_callbk = mark_cb;
 427         ft.ft_arg = ∓
 428         ft.ft_logfp = (ft_log_t)ndmp_log;
 429         ft.ft_flags = ndmpd_mark_flags;
 430 
 431         return (traverse(session, nlp, &ft));
 432 }
 433 
 434 
 435 /*
 436  * create_bitmap
 437  *
 438  * Create a dbitmap and return its descriptor.
 439  *
 440  * Parameters:
 441  *   path (input) - path for which the bitmap should be created
 442  *   value (input) - the initial value for the bitmap
 443  *
 444  * Returns:
 445  *   the dbitmap descriptor
 446  */
 447 static int
 448 create_bitmap(char *path, int value)
 449 {
 450         char bm_fname[PATH_MAX];
 451         char buf[TLM_MAX_PATH_NAME];
 452         char *livepath;
 453         ulong_t ninode;
 454 
 455         NDMP_LOG(LOG_DEBUG, "path \"%s\"", path);
 456 
 457         if (fs_is_chkpntvol(path))
 458                 livepath = (char *)tlm_remove_checkpoint(path, buf);
 459         else
 460                 livepath = path;
 461         ninode = 1024 * 1024 * 1024;
 462         if (ninode == 0)
 463                 return (-1);
 464         (void) ndmpd_mk_temp(bm_fname);
 465 
 466         NDMP_LOG(LOG_DEBUG, "path \"%s\"ninode %u bm_fname \"%s\"",
 467             livepath, ninode, bm_fname);
 468 
 469         return (dbm_alloc(bm_fname, (u_longlong_t)ninode, value));
 470 }
 471 
 472 
 473 /*
 474  * create_allset_bitmap
 475  *
 476  * A helper function to create a bitmap with all the
 477  * values set to 1.
 478  *
 479  * Parameters:
 480  *   nlp (input) - pointer to the nlp structure
 481  *
 482  * Returns:
 483  *   the dbitmap descriptor
 484  */
 485 static int
 486 create_allset_bitmap(ndmp_lbr_params_t *nlp)
 487 {
 488         int rv;
 489 
 490         nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 1);
 491         NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
 492 
 493         if (nlp->nlp_bkmap < 0) {
 494                 NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
 495                 rv = -1;
 496         } else
 497                 rv = 0;
 498 
 499         return (rv);
 500 }
 501 
 502 
 503 /*
 504  * mark_common_v2
 505  *
 506  * Create the inode bitmap.  If last date of the the
 507  * backup is epoch, then all the objects should be backed
 508  * up; there is no need to traverse the backup hierarchy
 509  * and mark the inodes.  All the bits should be marked.
 510  *
 511  * Otherwise, the backup hierarchy should be traversed and
 512  * the objects should be marked.
 513  *
 514  * Parameters:
 515  *   session (input) - pointer to the session
 516  *   nlp (input) - pointer to the nlp structure
 517  *
 518  * Returns:
 519  *   0: on success.
 520  *   != 0: on error.
 521  */
 522 static int
 523 mark_common_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
 524 {
 525         char buf[TLM_MAX_PATH_NAME], *chkpath;
 526         int rv;
 527 
 528         /*
 529          * Everything is needed for full backup.
 530          */
 531         if (nlp->nlp_ldate == (time_t)0)
 532                 return (create_allset_bitmap(nlp));
 533 
 534         rv = 0;
 535         nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
 536         NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
 537 
 538         if (nlp->nlp_bkmap < 0) {
 539                 NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
 540                 rv = -1;
 541         } else {
 542                 if (fs_is_chkpntvol(nlp->nlp_backup_path))
 543                         chkpath = nlp->nlp_backup_path;
 544                 else
 545                         chkpath = tlm_build_snapshot_name(
 546                             nlp->nlp_backup_path, buf,
 547                             nlp->nlp_jstat->js_job_name);
 548                 rv = mark_inodes_v2(session, nlp, chkpath);
 549                 (void) dbm_setone(nlp->nlp_bkmap, (u_longlong_t)ROOT_INODE);
 550         }
 551 
 552         return (rv);
 553 }
 554 
 555 
 556 /*
 557  * mark_tar_inodes_v2
 558  *
 559  * Create the bitmap for tar backup format.
 560  *
 561  * Parameters:
 562  *   session (input) - pointer to the session
 563  *   nlp (input) - pointer to the nlp structure
 564  *
 565  * Returns:
 566  *   0: on success.
 567  *   != 0: on error.
 568  */
 569 static int
 570 mark_tar_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
 571 {
 572         int rv;
 573 
 574         if (ndmp_tar_force_traverse)
 575                 rv = mark_common_v2(session, nlp);
 576         else
 577                 rv = create_allset_bitmap(nlp);
 578 
 579         return (rv);
 580 }
 581 
 582 
 583 /*
 584  * mark_dump_inodes_v2
 585  *
 586  * Create the bitmap for dump backup format.
 587  *
 588  * Parameters:
 589  *   session (input) - pointer to the session
 590  *   nlp (input) - pointer to the nlp structure
 591  *
 592  * Returns:
 593  *   0: on success.
 594  *   != 0: on error.
 595  */
 596 static int
 597 mark_dump_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
 598 {
 599         return (mark_common_v2(session, nlp));
 600 }
 601 
 602 
 603 /*
 604  * ndmpd_mark_inodes_v2
 605  *
 606  * Mark the inodes of the backup hierarchy if necessary.
 607  *
 608  * Parameters:
 609  *   session (input) - pointer to the session
 610  *   nlp (input) - pointer to the nlp structure
 611  *
 612  * Returns:
 613  *   0: on success.
 614  *   != 0: on error.
 615  */
 616 int
 617 ndmpd_mark_inodes_v2(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
 618 {
 619         int rv;
 620 
 621         if (ndmp_skip_traverse) {
 622                 NDMP_LOG(LOG_INFO, "Skip processing directories \"%s\"",
 623                     nlp->nlp_backup_path);
 624                 rv = create_allset_bitmap(nlp);
 625         } else {
 626                 if (NLP_ISTAR(nlp))
 627                         rv = mark_tar_inodes_v2(session, nlp);
 628                 else if (NLP_ISDUMP(nlp))
 629                         rv = mark_dump_inodes_v2(session, nlp);
 630                 else {
 631                         NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
 632                             nlp->nlp_backup_path);
 633                         rv = -1;
 634                 }
 635         }
 636 
 637         return (rv);
 638 }
 639 
 640 
 641 /*
 642  * ndmpd_abort_making_v2
 643  *
 644  * Abort the process of marking inodes.
 645  *
 646  * Parameters:
 647  *   session (input) - pointer to the session
 648  *
 649  * Returns:
 650  *   void
 651  */
 652 void
 653 ndmpd_abort_marking_v2(ndmpd_session_t *session)
 654 {
 655         ndmp_lbr_params_t *nlp;
 656 
 657         nlp = ndmp_get_nlp(session);
 658         if (nlp)
 659                 NLP_SET(nlp, NLPF_ABORTED);
 660 }
 661 
 662 
 663 /*
 664  * mark_tokv3
 665  *
 666  * Traverse the backup hierarchy and mark the bits for the
 667  * modified objects of directories leading to a modified
 668  * object for the token-based backup.
 669  *
 670  * Parameters:
 671  *   session (input) - pointer to the session
 672  *   nlp (input) - pointer to the nlp structure
 673  *   path (input) - the physical path to traverse
 674  *
 675  * Returns:
 676  *   0: on success
 677  *   != 0: otherwise
 678  */
 679 int
 680 mark_tokv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
 681 {
 682         fs_traverse_t ft;
 683         mark_param_t mp;
 684 
 685         if (!session || !nlp || !path || !*path) {
 686                 NDMP_LOG(LOG_DEBUG, "Invalid argument");
 687                 return (-1);
 688         }
 689         if (nlp->nlp_tokdate == (time_t)0)
 690                 return (create_allset_bitmap(nlp));
 691 
 692         nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
 693         if (nlp->nlp_bkmap < 0) {
 694                 NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
 695                 return (-1);
 696         }
 697         NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
 698 
 699         mp.mp_bmd = nlp->nlp_bkmap;
 700         mp.mp_ddate = nlp->nlp_tokdate;
 701         mp.mp_session = session;
 702         mp.mp_nlp = nlp;
 703 
 704         ft.ft_path = path;
 705         ft.ft_lpath = nlp->nlp_backup_path;
 706         ft.ft_callbk = mark_cb;
 707         ft.ft_arg = ∓
 708         ft.ft_logfp = (ft_log_t)ndmp_log;
 709         ft.ft_flags = ndmpd_mark_flags;
 710 
 711         return (traverse(session, nlp, &ft));
 712 }
 713 
 714 
 715 /*
 716  * marklbrv3_cb
 717  *
 718  * The callback function, called by traverse_post to mark
 719  * bits in the bitmap.
 720  *
 721  * It's so much like mark_cb for time-based (token-based
 722  * and level-type) backup types, except that it looks at
 723  * the archive bit of the objects instead of their timestamp.
 724  *
 725  * Parameters:
 726  *   arg (input) - pointer to the mark parameter
 727  *   pnp (input) - pointer to the path node
 728  *   enp (input) - pointer to the entry node
 729  *
 730  * Returns:
 731  *   0: as long as traversing should continue
 732  *   != 0: if traversing should stop
 733  */
 734 int
 735 marklbrv3_cb(void *arg, fst_node_t *pnp, fst_node_t *enp)
 736 {
 737         int bmd;
 738         u_longlong_t bl;
 739         fs_fhandle_t *pfhp, *efhp;
 740         struct stat64 *pstp, *estp;
 741         mark_param_t *mpp;
 742         ndmp_lbr_params_t *nlp;
 743 
 744         mpp = (mark_param_t *)arg;
 745         if (!mpp) {
 746                 NDMP_LOG(LOG_DEBUG, "NULL argument passed");
 747                 return (-1);
 748         }
 749         nlp = ndmp_get_nlp(mpp->mp_session);
 750         if (mpp->mp_session->ns_data.dd_abort ||
 751             (nlp && NLP_ISSET(nlp, NLPF_ABORTED))) {
 752                 NDMP_LOG(LOG_INFO, "Processing directories aborted.");
 753                 return (-1);
 754         }
 755 
 756         bmd = mpp->mp_bmd;
 757         bl = dbm_getlen(bmd);
 758 
 759         pfhp = pnp->tn_fh;
 760         pstp = pnp->tn_st;
 761 
 762         /* sanity check on fh and stat of the path passed */
 763         if (pstp->st_ino > bl) {
 764                 NDMP_LOG(LOG_DEBUG, "Invalid path inode #%u",
 765                     (uint_t)pstp->st_ino);
 766                 return (-1);
 767         }
 768         if (pstp->st_ino != pfhp->fh_fid) {
 769                 NDMP_LOG(LOG_DEBUG, "Path ino mismatch %u %u",
 770                     (uint_t)pstp->st_ino, (uint_t)pfhp->fh_fid);
 771                 return (-1);
 772         }
 773 
 774         /*
 775          * Always mark the backup path inode number.
 776          */
 777         if (!enp->tn_path) {
 778                 (void) dbm_setone(bmd, pstp->st_ino);
 779                 if (ndmpd_verbose_traverse) {
 780                         NDMP_LOG(LOG_DEBUG, "d(%u)", (uint_t)pstp->st_ino);
 781                         NDMP_LOG(LOG_DEBUG, "\"%s\"", pnp->tn_path);
 782                 }
 783                 return (0);
 784         }
 785 
 786         efhp = enp->tn_fh;
 787         estp = enp->tn_st;
 788 
 789         /* sanity check on fh and stat of the entry passed */
 790         if (estp->st_ino > bl) {
 791                 NDMP_LOG(LOG_DEBUG, "Invalid entry inode #%u",
 792                     (uint_t)estp->st_ino);
 793                 return (-1);
 794         }
 795         if (estp->st_ino != efhp->fh_fid) {
 796                 NDMP_LOG(LOG_DEBUG, "Entry ino mismatch %u %u", estp->st_ino,
 797                     (uint_t)pfhp->fh_fid);
 798                 return (-1);
 799         }
 800 
 801         if (S_ISDIR(estp->st_mode) &&
 802             dbm_getone(bmd, (u_longlong_t)estp->st_ino)) {
 803                 (void) dbm_setone(bmd, (u_longlong_t)pstp->st_ino);
 804                 if (ndmpd_verbose_traverse) {
 805                         NDMP_LOG(LOG_DEBUG, "d(%u,%u)",
 806                             (uint_t)pstp->st_ino, (uint_t)estp->st_ino);
 807                         NDMP_LOG(LOG_DEBUG, "\"%s, %s\"",
 808                             pnp->tn_path, enp->tn_path);
 809                 }
 810         }
 811 
 812         return (0);
 813 }
 814 
 815 
 816 /*
 817  * mark_lbrv3
 818  *
 819  * Traverse the backup hierarchy and mark the bits for the
 820  * modified objects of directories leading to a modified
 821  * object for the LBR-type backup.
 822  *
 823  * Parameters:
 824  *   session (input) - pointer to the session
 825  *   nlp (input) - pointer to the nlp structure
 826  *   path (input) - the physical path to traverse
 827  *
 828  * Returns:
 829  *   0: on success
 830  *   != 0: otherwise
 831  */
 832 int
 833 mark_lbrv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
 834 {
 835         char c;
 836         fs_traverse_t ft;
 837         mark_param_t mp;
 838 
 839         if (!session || !nlp || !path || !*path) {
 840                 NDMP_LOG(LOG_DEBUG, "Invalid argument");
 841                 return (-1);
 842         }
 843         /* full and archive backups backup everything */
 844         c = toupper(nlp->nlp_clevel);
 845         if (c == 'F' || c == 'A')
 846                 return (create_allset_bitmap(nlp));
 847 
 848         nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
 849         if (nlp->nlp_bkmap < 0) {
 850                 NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
 851                 return (-1);
 852         }
 853         NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
 854 
 855         mp.mp_bmd = nlp->nlp_bkmap;
 856         mp.mp_ddate = 0;
 857         mp.mp_session = session;
 858         mp.mp_nlp = nlp;
 859 
 860         ft.ft_path = path;
 861         ft.ft_lpath = nlp->nlp_backup_path;
 862         ft.ft_callbk = marklbrv3_cb;
 863         ft.ft_arg = ∓
 864         ft.ft_logfp = (ft_log_t)ndmp_log;
 865         ft.ft_flags = ndmpd_mark_flags;
 866 
 867         return (traverse(session, nlp, &ft));
 868 }
 869 
 870 
 871 /*
 872  * mark_levelv3
 873  *
 874  * Traverse the backup hierarchy and mark the bits for the
 875  * modified objects of directories leading to a modified
 876  * object for the level-type backup.
 877  *
 878  * Parameters:
 879  *   session (input) - pointer to the session
 880  *   nlp (input) - pointer to the nlp structure
 881  *   path (input) - the physical path to traverse
 882  *
 883  * Returns:
 884  *   0: on success
 885  *   != 0: otherwise
 886  */
 887 int
 888 mark_levelv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp, char *path)
 889 {
 890         fs_traverse_t ft;
 891         mark_param_t mp;
 892         tlm_acls_t traverse_acl;
 893 
 894         if (!session || !nlp || !path || !*path) {
 895                 NDMP_LOG(LOG_DEBUG, "Invalid argument");
 896                 return (-1);
 897         }
 898         if (nlp->nlp_ldate == (time_t)0)
 899                 return (create_allset_bitmap(nlp));
 900 
 901         nlp->nlp_bkmap = create_bitmap(nlp->nlp_backup_path, 0);
 902         if (nlp->nlp_bkmap < 0) {
 903                 NDMP_LOG(LOG_DEBUG, "Failed to allocate bitmap.");
 904                 return (-1);
 905         }
 906         NDMP_LOG(LOG_DEBUG, "nlp_bkmap %d", nlp->nlp_bkmap);
 907 
 908         /*
 909          * We do not want to allocate memory for acl every time we
 910          * process a file.
 911          */
 912         (void) memset(&traverse_acl, 0, sizeof (traverse_acl));
 913         mp.mp_tacl = &traverse_acl;
 914 
 915         mp.mp_bmd = nlp->nlp_bkmap;
 916         mp.mp_ddate = nlp->nlp_ldate;
 917         mp.mp_session = session;
 918         mp.mp_nlp = nlp;
 919 
 920         ft.ft_path = path;
 921         ft.ft_lpath = nlp->nlp_backup_path;
 922         ft.ft_callbk = mark_cb;
 923         ft.ft_arg = ∓
 924         ft.ft_logfp = (ft_log_t)ndmp_log;
 925         ft.ft_flags = ndmpd_mark_flags;
 926 
 927         return (traverse(session, nlp, &ft));
 928 }
 929 
 930 
 931 /*
 932  * mark_commonv3
 933  *
 934  * Create the inode bitmap.  If last date of the the
 935  * backup is epoch, then all the objects should be backed
 936  * up; there is no need to traverse the backup hierarchy
 937  * and mark the inodes.  All the bits should be marked.
 938  *
 939  * Otherwise, the backup hierarchy should be traversed and
 940  * the objects should be marked.
 941  *
 942  * Parameters:
 943  *   session (input) - pointer to the session
 944  *   nlp (input) - pointer to the nlp structure
 945  *
 946  * Returns:
 947  *   0: on success.
 948  *   != 0: on error.
 949  */
 950 int
 951 mark_commonv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
 952 {
 953         char buf[TLM_MAX_PATH_NAME], *chkpath;
 954         int rv;
 955 
 956         if (NLP_ISCHKPNTED(nlp))
 957                 chkpath = nlp->nlp_backup_path;
 958         else
 959                 chkpath = tlm_build_snapshot_name(nlp->nlp_backup_path, buf,
 960                     nlp->nlp_jstat->js_job_name);
 961 
 962         if (NLP_ISSET(nlp, NLPF_TOKENBK))
 963                 rv = mark_tokv3(session, nlp, chkpath);
 964         else if (NLP_ISSET(nlp, NLPF_LBRBK))
 965                 rv = mark_lbrv3(session, nlp, chkpath);
 966         else if (NLP_ISSET(nlp, NLPF_LEVELBK)) {
 967                 rv = mark_levelv3(session, nlp, chkpath);
 968         } else {
 969                 rv = -1;
 970                 NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
 971                     nlp->nlp_backup_path);
 972         }
 973 
 974         return (rv);
 975 }
 976 
 977 
 978 /*
 979  * mark_tar_inodesv3
 980  *
 981  * Mark bits for tar backup format of V3.  Normally, the
 982  * backup hierarchy is not traversed for tar format
 983  * unless it's forced by setting the ndmp_tar_force_traverse
 984  * to a non-zero value.
 985  *
 986  * Parameters:
 987  *   session (input) - pointer to the session
 988  *   nlp (input) - pointer to the nlp structure
 989  *
 990  * Returns:
 991  *   0: on success
 992  *   != 0: otherwise
 993  */
 994 int
 995 mark_tar_inodesv3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
 996 {
 997         int rv;
 998 
 999         if (ndmp_tar_force_traverse)
1000                 rv = mark_commonv3(session, nlp);
1001         else
1002                 rv = create_allset_bitmap(nlp);
1003 
1004         return (rv);
1005 }
1006 
1007 
1008 /*
1009  * ndmpd_mark_inodes_v3
1010  *
1011  * Mark the inodes of the backup hierarchy if necessary.
1012  *
1013  * Parameters:
1014  *   session (input) - pointer to the session
1015  *   nlp (input) - pointer to the nlp structure
1016  *
1017  * Returns:
1018  *   0: on success.
1019  *   != 0: on error.
1020  */
1021 int
1022 ndmpd_mark_inodes_v3(ndmpd_session_t *session, ndmp_lbr_params_t *nlp)
1023 {
1024         int rv;
1025 
1026         if (ndmp_skip_traverse) {
1027                 NDMP_LOG(LOG_INFO, "Skip processing directories \"%s\"",
1028                     nlp->nlp_backup_path);
1029                 rv = create_allset_bitmap(nlp);
1030         } else {
1031                 if (NLP_ISTAR(nlp))
1032                         rv = mark_tar_inodesv3(session, nlp);
1033                 else if (NLP_ISDUMP(nlp)) {
1034                         rv = mark_commonv3(session, nlp);
1035                 } else {
1036                         NDMP_LOG(LOG_DEBUG, "Unknown backup type for \"%s\"",
1037                             nlp->nlp_backup_path);
1038                         rv = -1;
1039                 }
1040         }
1041 
1042         return (rv);
1043 }