1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License, Version 1.0 only
   6  * (the "License").  You may not use this file except in compliance
   7  * with the License.
   8  *
   9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  10  * or http://www.opensolaris.org/os/licensing.
  11  * See the License for the specific language governing permissions
  12  * and limitations under the License.
  13  *
  14  * When distributing Covered Code, include this CDDL HEADER in each
  15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  16  * If applicable, add the following below this CDDL HEADER, with the
  17  * fields enclosed by brackets "[]" replaced with your own identifying
  18  * information: Portions Copyright [yyyy] [name of copyright owner]
  19  *
  20  * CDDL HEADER END
  21  */
  22 /*
  23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
  28 /*          All Rights Reserved */
  29 
  30 /*
  31  * Portions of this source code were derived from Berkeley 4.3 BSD
  32  * under license from the Regents of the University of California.
  33  */
  34 
  35 #pragma ident   "%Z%%M% %I%     %E% SMI"
  36 
  37 /*
  38  *
  39  *                      fsck.c
  40  *
  41  * Cachefs fsck program.
  42  */
  43 
  44 #include <locale.h>
  45 #include <stdio.h>
  46 #include <stdlib.h>
  47 #include <string.h>
  48 #include <assert.h>
  49 #include <stdarg.h>
  50 #include <unistd.h>
  51 #include <limits.h>
  52 #include <errno.h>
  53 #include <wait.h>
  54 #include <ctype.h>
  55 #include <fcntl.h>
  56 #include <ftw.h>
  57 #include <dirent.h>
  58 #include <search.h>
  59 #include <sys/types.h>
  60 #include <sys/uio.h>
  61 #include <sys/param.h>
  62 #include <sys/stat.h>
  63 #include <sys/fcntl.h>
  64 #include <sys/mount.h>
  65 #include <sys/mntent.h>
  66 #include <sys/mnttab.h>
  67 #include <sys/mman.h>
  68 #include <sys/fs/cachefs_fs.h>
  69 #include <syslog.h>
  70 #include "../common/subr.h"
  71 #include "res.h"
  72 
  73 char *cfs_opts[] = {
  74 #define         CFSOPT_PREEN            0
  75                 "preen",
  76 #define         CFSOPT_NOCLEAN          1
  77                 "noclean",
  78 #define         CFSOPT_VERBOSE          2
  79                 "verbose",
  80 #define         CFSOPT_NONOCLEAN        3
  81                 "nonoclean",
  82 
  83                 NULL
  84 };
  85 
  86 extern int dlog_ck(char *dir_path, ino64_t *maxlocalfilenop);
  87 
  88 /* forward references */
  89 void usage(char *msgp);
  90 void pr_err(char *fmt, ...);
  91 int cfs_check(char *cachedirp, int noclean, int mflag, int verbose,
  92     int nonoclean);
  93 int cache_label_file(char *cachedirp, struct cache_label *clabelp);
  94 int cache_permissions(char *cachedirp);
  95 int cache_check_dir(char *cachedirp, char *namep);
  96 int process_fsdir(char *cachedirp, char *namep, res *resp, int verbose);
  97 int process_fsinfo(char *namep, ino64_t maxlocalfileno,
  98     cachefs_fsinfo_t *fsinfop, int verbose);
  99 int process_fsgroup(char *dirp, char *namep, res *resp, ino64_t base,
 100     int fgsize, ino64_t fsid, int local, int verbose);
 101 int tree_remove(const char *namep, const struct stat64 *statp, int type,
 102     struct FTW *ftwp);
 103 int cache_upgrade(char *cachedirp, int lockid);
 104 int file_remove(const char *namep, const struct stat64 *statp, int verbose);
 105 void cache_backmnt_cleanup(char *cachedirp, char *backmnt_namep);
 106 
 107 #define FLAGS_FTW (FTW_PHYS | FTW_MOUNT | FTW_DEPTH)
 108 
 109 static int S_verbose = 0;
 110 static char S_lostfound[MAXPATHLEN];
 111 static int S_move_lostfound = 0;
 112 
 113 /*
 114  *
 115  *                      main
 116  *
 117  * Description:
 118  *      Main routine for the cachefs fsck program.
 119  * Arguments:
 120  *      argc    number of command line arguments
 121  *      argv    list of command line arguments
 122  * Returns:
 123  *      Returns:
 124  *               0      file system is okay and does not need checking
 125  *               1      problem unrelated to the file system
 126  *              32      file system is unmounted and needs checking  (fsck
 127  *                      -m only)
 128  *              33      file system is already mounted
 129  *              34      cannot stat device
 130  *              36      uncorrectable errors detected - terminate normally
 131  *              37      a signal was caught during processing
 132  *              39      uncorrectable errors detected - terminate  immediately
 133  *              40      for root mounted fs, same as 0
 134  * Preconditions:
 135  */
 136 
 137 int
 138 main(int argc, char **argv)
 139 {
 140         int xx;
 141         int c;
 142         char *optionp;
 143         char *valuep;
 144         int mflag;
 145         int noclean;
 146         char *cachedirp;
 147         int lockid;
 148         int verbose;
 149         int nonoclean;
 150 
 151         (void) setlocale(LC_ALL, "");
 152 #if !defined(TEXT_DOMAIN)
 153 #define TEXT_DOMAIN     "SYS_TEST"
 154 #endif
 155         (void) textdomain(TEXT_DOMAIN);
 156 
 157         /* verify root running command */
 158         if (getuid() != 0) {
 159                 fprintf(stderr, gettext(
 160                         "fsck -F cachefs: must be run by root\n"));
 161                 return (1);
 162         }
 163 
 164         /* process command line options */
 165         optionp = NULL;
 166         mflag = 0;
 167         noclean = 0;
 168         verbose = 0;
 169         nonoclean = 0;
 170         while ((c = getopt(argc, argv, "mnNo:yY")) != EOF) {
 171                 switch (c) {
 172                 case 'm':       /* check but do not repair */
 173                         mflag = 1;
 174                         break;
 175 
 176                 case 'n':       /* answer no to questions */
 177                 case 'N':
 178                         /* ignored */
 179                         break;
 180 
 181                 case 'o':
 182                         optionp = optarg;
 183                         while (*optionp) {
 184                                 xx = getsubopt(&optionp, cfs_opts, &valuep);
 185                                 switch (xx) {
 186                                 case CFSOPT_PREEN:
 187                                         /* preen is the default mode */
 188                                         break;
 189                                 case CFSOPT_NOCLEAN:
 190                                         noclean = 1;
 191                                         break;
 192                                 case CFSOPT_VERBOSE:
 193                                         verbose++;
 194                                         S_verbose++;
 195                                         break;
 196                                 case CFSOPT_NONOCLEAN:
 197                                         nonoclean = 1;
 198                                         break;
 199                                 default:
 200                                 case -1:
 201                                         pr_err(gettext("unknown option %s"),
 202                                             valuep);
 203                                         return (1);
 204                                 }
 205                         }
 206                         break;
 207 
 208                 case 'y':       /* answer yes to questions */
 209                 case 'Y':
 210                         /* ignored, this is the default */
 211                         break;
 212 
 213                 default:
 214                         usage("invalid option");
 215                         return (1);
 216                 }
 217         }
 218 
 219         /* verify fsck device is specified */
 220         if (argc - optind < 1) {
 221                 usage(gettext("must specify cache directory"));
 222                 return (1);
 223         }
 224 
 225         /* save cache directory */
 226         cachedirp = argv[argc - 1];
 227 
 228         /* ensure cache directory exists */
 229         if (access(cachedirp, F_OK) != 0) {
 230                 pr_err(gettext("Cache directory %s does not exist."),
 231                     cachedirp);
 232                 return (39);
 233         }
 234 
 235         /* lock the cache directory non-shared */
 236         lockid = cachefs_dir_lock(cachedirp, 0);
 237         if (lockid == -1) {
 238                 /* exit if could not get the lock */
 239                 return (1);
 240         }
 241 
 242         /* is the cache directory in use */
 243         if (cachefs_inuse(cachedirp)) {
 244                 if (noclean) {
 245                         pr_err(gettext("Cache directory %s is in use."),
 246                             cachedirp);
 247                         xx = 33;
 248                 } else {
 249                         /* assume if in use that it is clean */
 250                         xx = 0;
 251                 }
 252                 cachefs_dir_unlock(lockid);
 253                 return (xx);
 254         }
 255 
 256         xx = cache_upgrade(cachedirp, lockid);
 257         if (xx != 0) {
 258                 /* check the file system */
 259                 xx = cfs_check(cachedirp, noclean, mflag, verbose, nonoclean);
 260         }
 261 
 262         /* unlock the cache directory */
 263         cachefs_dir_unlock(lockid);
 264 
 265         /* inform if files moved to lost+found */
 266         if (S_move_lostfound) {
 267                 pr_err(gettext("Files recovered to %s"), S_lostfound);
 268         }
 269 
 270         /* return the status of the file system checking */
 271         return (xx);
 272 }
 273 
 274 /*
 275  *
 276  *                      usage
 277  *
 278  * Description:
 279  *      Prints a short usage message.
 280  * Arguments:
 281  *      msgp    message to include with the usage message
 282  * Returns:
 283  * Preconditions:
 284  */
 285 
 286 void
 287 usage(char *msgp)
 288 {
 289         if (msgp) {
 290                 pr_err("%s", msgp);
 291         }
 292 
 293         (void) fprintf(stderr,
 294             gettext("Usage: fsck -F cachefs [ -o specific_options ] [ -m ] "
 295             "cachedir\n"));
 296 }
 297 
 298 /*
 299  *
 300  *                      pr_err
 301  *
 302  * Description:
 303  *      Prints an error message to stderr.
 304  * Arguments:
 305  *      fmt     printf style format
 306  *      ...     arguments for fmt
 307  * Returns:
 308  * Preconditions:
 309  *      precond(fmt)
 310  */
 311 
 312 void
 313 pr_err(char *fmt, ...)
 314 {
 315         va_list ap;
 316 
 317         va_start(ap, fmt);
 318         (void) fprintf(stderr, gettext("fsck -F cachefs: "));
 319         (void) vfprintf(stderr, fmt, ap);
 320         (void) fprintf(stderr, "\n");
 321         va_end(ap);
 322 }
 323 
 324 /*
 325  *
 326  *                      cache_upgrade
 327  *
 328  * Description:
 329  *
 330  *      See if the current cache is out of date.  If it is, do
 331  *      whatever magic is necessary to upgrade it.  All such magic
 332  *      should be encapsulated here!
 333  *
 334  * Arguments:
 335  *
 336  *      cachedirp       name of the cache directory to check
 337  *
 338  * Returns:
 339  *      Returns:
 340  *               0      cache was upgraded and shouldn't be checked
 341  *               1      problem unrelated to the file system
 342  *              36      uncorrectable errors detected - terminate normally
 343  *              39      uncorrectable errors detected - terminate  immediately
 344  *              50      cache was already up-to-date (maybe we should fsck it)
 345  *              51      cache was upgraded (but you should do fsck)
 346  * Preconditions:
 347  *      precond(cachedirp)
 348  */
 349 
 350 int
 351 cache_upgrade(char *cachedirp, int lockid)
 352 {
 353 #ifdef CFSRLDEBUG
 354         static int canupgrade[] = {1, 2, 3, 103, 104, 105, 106, 107,
 355             4, 5, 108, 6, 7, 8, 0};
 356 #else /* CFSRLDEBUG */
 357         static int canupgrade[] = {1, 2, 3, 103, 104, 105, 106, 107,
 358             4, 108, 5, 109, 110, 6, 111, 0};
 359 #endif /* CFSRLDEBUG */
 360         char labelpath[MAXPATHLEN];
 361         struct cache_label clabel;
 362         int i;
 363 
 364         if (((int)strlen(cachedirp) + (int)strlen(CACHELABEL_NAME) + 2)
 365             >= MAXPATHLEN)
 366                 return (1);
 367 
 368         (void) sprintf(labelpath, "%s/%s", cachedirp, CACHELABEL_NAME);
 369 
 370         if (cachefs_label_file_get(labelpath, &clabel) != 0)
 371                 return (1);
 372 
 373         /* nothing to do if we're current */
 374         if (clabel.cl_cfsversion == CFSVERSION)
 375                 return (50);
 376 
 377         /* see if it's an old version that we know how to upgrade */
 378         for (i = 0; canupgrade[i] != 0; i++)
 379                 if (clabel.cl_cfsversion == canupgrade[i])
 380                         break;
 381         if (canupgrade[i] == 0)
 382                 return (36);
 383 
 384         syslog(LOG_USER | LOG_INFO,
 385             gettext("fsck -F cachefs: Recreating cache %s"), cachedirp);
 386 
 387         /* currently, to `upgrade' we delete the old cache */
 388         if (cachefs_delete_all_cache(cachedirp) != 0)
 389                 return (36);
 390 
 391         /* do any magic necessary to convert the old label to the new one */
 392         clabel.cl_cfsversion = CFSVERSION;
 393 
 394         /* create the new cache! */
 395         if (cachefs_create_cache(cachedirp, NULL, &clabel) != 0)
 396                 return (36);
 397 
 398         return (0);
 399 }
 400 
 401 /*
 402  *
 403  *                      cfs_check
 404  *
 405  * Description:
 406  *      This routine performs the actual checking of the cache
 407  *      file system.
 408  *      The file system must be inactive when this routine is called.
 409  * Arguments:
 410  *      cachedirp       name of the cache directory to check
 411  *      noclean         1 means ignore clean flag
 412  *      mflag           1 means no fixes, only check if mountable
 413  *      verbose         indicate level of verbosity for diagnostics
 414  *      nonoclean       1 means honor clean flag; don't by default
 415  * Returns:
 416  *      Returns:
 417  *               0      file system is okay and does not need checking
 418  *               1      problem unrelated to the file system
 419  *              32      file system is unmounted and needs checking
 420  *              33      file system is already mounted
 421  *              34      cannot stat device
 422  *              36      uncorrectable errors detected - terminate normally
 423  *              37      a signal was caught during processing
 424  *              39      uncorrectable errors detected - terminate  immediately
 425  *              40      for root mounted fs, same as 0, XXX
 426  * Preconditions:
 427  *      precond(cachedirp)
 428  */
 429 
 430 int
 431 cfs_check(char *cachedirp, int noclean, int mflag, int verbose, int nonoclean)
 432 {
 433         DIR *dp;
 434         struct dirent64 *dep;
 435         char buf[MAXPATHLEN];
 436         struct stat64 statinfo;
 437         int xx;
 438         char *namep;
 439         res *resp;
 440         struct cache_label clabel;
 441 
 442         /* if checking the clean flag is sufficient */
 443         if ((noclean == 0) && (nonoclean || mflag)) {
 444                 /* if the clean flag is set */
 445                 if (cachefs_clean_flag_test(cachedirp)) {
 446                         if (verbose) {
 447                                 pr_err(gettext("Cache %s is clean"), cachedirp);
 448                         }
 449                         return (0);
 450                 }
 451         }
 452 
 453         /* if mflag specified then go no farther */
 454         if (mflag)
 455                 return (32);
 456 
 457         /* check the cache label file for correctness */
 458         xx = cache_label_file(cachedirp, &clabel);
 459         if (xx)
 460                 return (xx);
 461 
 462         /* make sure the kernel lock file exists */
 463         sprintf(buf, "%s/%s", cachedirp, CACHEFS_LOCK_FILE);
 464         xx = open(buf, O_RDWR | O_CREAT, 0700);
 465         if (xx == -1) {
 466                 pr_err(gettext("Cannot create lock file %s"), buf);
 467                 return (39);
 468         }
 469         close(xx);
 470 
 471         /* fix permissions on the cache directory */
 472         xx = cache_permissions(cachedirp);
 473         if (xx)
 474                 return (xx);
 475 
 476         /* make the back file system mount directory if necessary */
 477         xx = cache_check_dir(cachedirp, BACKMNT_NAME);
 478         if (xx)
 479                 return (xx);
 480 
 481         /* clean out junk in the back file system mount directory */
 482         cache_backmnt_cleanup(cachedirp, BACKMNT_NAME);
 483 
 484         /* make the lost+found directory if necessary */
 485         xx = cache_check_dir(cachedirp, CACHEFS_LOSTFOUND_NAME);
 486         if (xx)
 487                 return (xx);
 488 
 489         /* construct the path to the lost and found directory for file_remove */
 490         sprintf(S_lostfound, "%s/%s", cachedirp, CACHEFS_LOSTFOUND_NAME);
 491 
 492         /* construct the path name of the resource file */
 493         namep = RESOURCE_NAME;
 494         xx = strlen(cachedirp) + strlen(namep) + 3;
 495         if (xx >= MAXPATHLEN) {
 496                 pr_err(gettext("Path name too long %s/%s"),
 497                     cachedirp, namep);
 498                 return (39);
 499         }
 500         sprintf(buf, "%s/%s", cachedirp, namep);
 501 
 502         /* make a res object to operate on the resource file */
 503         resp = res_create(buf, clabel.cl_maxinodes, verbose);
 504         if (resp == NULL) {
 505                 pr_err(gettext("Could not process resource file %s: %s"),
 506                     buf, strerror(errno));
 507                 return (39);
 508         }
 509 
 510         /* open the cache directory */
 511         if ((dp = opendir(cachedirp)) == NULL) {
 512                 pr_err(gettext("Cannot open directory %s: %s"), cachedirp,
 513                     strerror(errno));
 514                 res_destroy(resp);
 515                 return (39);
 516         }
 517 
 518         /* mark all directories */
 519         while ((dep = readdir64(dp)) != NULL) {
 520                 /* ignore . and .. */
 521                 if ((strcmp(dep->d_name, ".") == 0) ||
 522                                 (strcmp(dep->d_name, "..") == 0))
 523                         continue;
 524 
 525                 /* check path length */
 526                 xx = strlen(cachedirp) + strlen(dep->d_name) + 3;
 527                 if (xx >= MAXPATHLEN) {
 528                         pr_err(gettext("Path name too long %s/%s"),
 529                             cachedirp, dep->d_name);
 530                         closedir(dp);
 531                         res_destroy(resp);
 532                         return (39);
 533                 }
 534 
 535                 /* stat the file */
 536                 sprintf(buf, "%s/%s", cachedirp, dep->d_name);
 537                 xx = lstat64(buf, &statinfo);
 538                 if (xx == -1) {
 539                         if (errno != ENOENT) {
 540                                 pr_err(gettext("Cannot stat %s: %s"), cachedirp,
 541                                     strerror(errno));
 542                                 closedir(dp);
 543                                 res_destroy(resp);
 544                                 return (39);
 545                         }
 546                         continue;
 547                 }
 548 
 549                 /* if a directory */
 550                 if (S_ISDIR(statinfo.st_mode)) {
 551                         xx = chmod(buf, 0700);
 552                         if (xx == -1) {
 553                                 pr_err(gettext("Cannot chmod %s: %s"), buf,
 554                                     strerror(errno));
 555                                 closedir(dp);
 556                                 res_destroy(resp);
 557                                 return (39);
 558                         }
 559                 }
 560         }
 561 
 562         /* process files in the cache directory */
 563         rewinddir(dp);
 564         while ((dep = readdir64(dp)) != NULL) {
 565                 /* ignore . and .. */
 566                 if ((strcmp(dep->d_name, ".") == 0) ||
 567                                 (strcmp(dep->d_name, "..") == 0))
 568                         continue;
 569 
 570                 /* stat the file */
 571                 sprintf(buf, "%s/%s", cachedirp, dep->d_name);
 572                 xx = lstat64(buf, &statinfo);
 573                 if (xx == -1) {
 574                         if (errno != ENOENT) {
 575                                 pr_err(gettext("Cannot stat %s: %s"), cachedirp,
 576                                     strerror(errno));
 577                                 closedir(dp);
 578                                 res_destroy(resp);
 579                                 return (39);
 580                         }
 581                         continue;
 582                 }
 583 
 584                 /* ignore directories */
 585                 if (S_ISDIR(statinfo.st_mode))
 586                         continue;
 587 
 588                 /* if not a link */
 589                 if (!S_ISLNK(statinfo.st_mode)) {
 590                         /*
 591                          * XXX make sure a valid file
 592                          * Update file and block counts for this file.
 593                          * This file will be <2GB.
 594                          */
 595                         res_addfile(resp, (long)statinfo.st_size);
 596                         continue;
 597                 }
 598 
 599                 /* process the file system cache directory */
 600                 xx = process_fsdir(cachedirp, dep->d_name, resp, verbose);
 601                 if (xx) {
 602                         closedir(dp);
 603                         res_destroy(resp);
 604                         return (xx);
 605                 }
 606         }
 607 
 608         /* look for directories that do not belong */
 609         rewinddir(dp);
 610         while ((dep = readdir64(dp)) != NULL) {
 611                 /* ignore . and .. */
 612                 if ((strcmp(dep->d_name, ".") == 0) ||
 613                                 (strcmp(dep->d_name, "..") == 0))
 614                         continue;
 615 
 616                 /* stat the file */
 617                 sprintf(buf, "%s/%s", cachedirp, dep->d_name);
 618                 xx = lstat64(buf, &statinfo);
 619                 if (xx == -1) {
 620                         if (errno != ENOENT) {
 621                                 pr_err(gettext("Cannot stat %s: %s"), cachedirp,
 622                                     strerror(errno));
 623                                 closedir(dp);
 624                                 res_destroy(resp);
 625                                 return (39);
 626                         }
 627                         continue;
 628                 }
 629 
 630                 /* XXX should we unlink extraneous regular files? */
 631 
 632                 /* ignore all but directories */
 633                 if (!S_ISDIR(statinfo.st_mode))
 634                         continue;
 635 
 636                 /* ignore directories we have checked */
 637                 if ((statinfo.st_mode & S_IAMB) != 0700)
 638                         continue;
 639 
 640                 /* ignore the mount directory */
 641                 if (strcmp(dep->d_name, BACKMNT_NAME) == 0)
 642                         continue;
 643 
 644                 /* ignore the lost+found directory */
 645                 if (strcmp(dep->d_name, CACHEFS_LOSTFOUND_NAME) == 0)
 646                         continue;
 647 
 648                 /* remove the directory */
 649                 xx = nftw64(buf, tree_remove, 3, FLAGS_FTW);
 650                 if (xx != 0) {
 651                         pr_err(gettext("Error walking tree %s."), namep);
 652                         closedir(dp);
 653                         res_destroy(resp);
 654                         return (39);
 655                 }
 656 
 657                 if (verbose)
 658                         pr_err(gettext("Directory removed: %s"), buf);
 659         }
 660 
 661         /* close the directory */
 662         closedir(dp);
 663 
 664         /* add one file and one block for the cache directory itself */
 665         res_addfile(resp, 1);
 666 
 667         /* finish off the resource file processing */
 668         xx = res_done(resp);
 669         if (xx == -1) {
 670                 pr_err(gettext("Could not finish resource file %s: %s"),
 671                     buf, strerror(errno));
 672                 return (39);
 673         }
 674         res_destroy(resp);
 675 
 676         /* return success */
 677         return (0);
 678 }
 679 
 680 /*
 681  *
 682  *                      cache_label_file
 683  *
 684  * Description:
 685  *      This routine performs the checking and fixing up of the
 686  *      cache label file.
 687  * Arguments:
 688  *      cachedirp       name of the cache directory to check
 689  *      clabelp         cache label contents put here if not NULL
 690  * Returns:
 691  *               0      file system is okay and does not need checking
 692  *               1      problem unrelated to the file system
 693  *              32      file system is unmounted and needs checking
 694  *              33      file system is already mounted
 695  *              34      cannot stat device
 696  *              36      uncorrectable errors detected - terminate normally
 697  *              37      a signal was caught during processing
 698  *              39      uncorrectable errors detected - terminate  immediately
 699  * Preconditions:
 700  *      precond(cachedirp)
 701  */
 702 
 703 int
 704 cache_label_file(char *cachedirp, struct cache_label *clabelp)
 705 {
 706         int xx;
 707         char buf1[MAXPATHLEN];
 708         char buf2[MAXPATHLEN];
 709         char *namep;
 710         struct cache_label clabel1, clabel2;
 711 
 712         namep = CACHELABEL_NAME;
 713 
 714         /* see if path name is too long */
 715         xx = strlen(cachedirp) + strlen(namep) + 10;
 716         if (xx >= MAXPATHLEN) {
 717                 pr_err(gettext("Cache directory name %s is too long"),
 718                     cachedirp);
 719                 return (39);
 720         }
 721 
 722         /* make a path to the cache label file and its backup copy */
 723         sprintf(buf1, "%s/%s", cachedirp, namep);
 724         sprintf(buf2, "%s/%s.dup", cachedirp, namep);
 725 
 726         /* get the contents of the cache label file */
 727         xx = cachefs_label_file_get(buf1, &clabel1);
 728         if (xx == -1) {
 729                 /* get the backup cache label file contents */
 730                 xx = cachefs_label_file_get(buf2, &clabel2);
 731                 if (xx == -1) {
 732                         pr_err(gettext("Run `cfsadmin -d all %s'\n"
 733                             "and then run\n"
 734                             "`cfsadmin -c %s'\n"), cachedirp, cachedirp);
 735                         return (39);
 736                 }
 737 
 738                 /* write the cache label file */
 739                 xx = cachefs_label_file_put(buf1, &clabel2);
 740                 if (xx == -1) {
 741                         pr_err(gettext("Run `cfsadmin -d all %s'\n"
 742                             "and then run\n"
 743                             "`cfsadmin -c %s'\n"), cachedirp, cachedirp);
 744                         return (39);
 745                 }
 746                 pr_err(gettext("Cache label file %s repaired."), buf1);
 747 
 748                 /* copy out the contents to the caller */
 749                 if (clabelp)
 750                         *clabelp = clabel2;
 751 
 752                 /* return success */
 753                 return (0);
 754         }
 755 
 756         /* get the contents of the backup cache label file */
 757         xx = cachefs_label_file_get(buf2, &clabel2);
 758         if (xx == -1) {
 759                 /* write the backup cache label file */
 760                 xx = cachefs_label_file_put(buf2, &clabel1);
 761                 if (xx == -1) {
 762                         return (39);
 763                 }
 764                 pr_err(gettext("Cache label file %s repaired."), buf2);
 765         }
 766 
 767         /* copy out the contents to the caller */
 768         if (clabelp)
 769                 *clabelp = clabel1;
 770 
 771         /* return success */
 772         return (0);
 773 }
 774 
 775 /*
 776  *
 777  *                      cache_permissions
 778  *
 779  * Description:
 780  *      Checks the permissions on the cache directory and fixes
 781  *      them if necessary.
 782  * Arguments:
 783  *      cachedirp       name of the cache directory to check
 784  * Returns:
 785  *               0      file system is okay and does not need checking
 786  *               1      problem unrelated to the file system
 787  *              32      file system is unmounted and needs checking
 788  *              33      file system is already mounted
 789  *              34      cannot stat device
 790  *              36      uncorrectable errors detected - terminate normally
 791  *              37      a signal was caught during processing
 792  *              39      uncorrectable errors detected - terminate  immediately
 793  * Preconditions:
 794  *      precond(cachedirp)
 795  */
 796 
 797 int
 798 cache_permissions(char *cachedirp)
 799 {
 800         int xx;
 801         struct stat64 statinfo;
 802 
 803         /* get info about the cache directory */
 804         xx = lstat64(cachedirp, &statinfo);
 805         if (xx == -1) {
 806                 pr_err(gettext("Could not stat %s: %s"), cachedirp,
 807                     strerror(errno));
 808                 return (34);
 809         }
 810 
 811         /* check the mode bits */
 812         if ((statinfo.st_mode & S_IAMB) != 0) {
 813 
 814                 /* fix the mode bits */
 815                 xx = chmod(cachedirp, 0);
 816                 if (xx == -1) {
 817                         pr_err(gettext("Could not set modes bits on "
 818                             "cache directory %s: %s"),
 819                             cachedirp, strerror(errno));
 820                         return (36);
 821                 }
 822                 pr_err(gettext("Mode bits reset on cache directory %s"),
 823                     cachedirp);
 824         }
 825 
 826         /* return success */
 827         return (0);
 828 }
 829 
 830 /*
 831  *
 832  *                      cache_check_dir
 833  *
 834  * Description:
 835  *      Checks for the existance of the directory
 836  *      and creates it if necessary.
 837  * Arguments:
 838  *      cachedirp       name of the cache directory containing the dir
 839  *      namep           name of dir
 840  * Returns:
 841  *               0      file system is okay and does not need checking
 842  *               1      problem unrelated to the file system
 843  *              32      file system is unmounted and needs checking
 844  *              33      file system is already mounted
 845  *              34      cannot stat device
 846  *              36      uncorrectable errors detected - terminate normally
 847  *              37      a signal was caught during processing
 848  *              39      uncorrectable errors detected - terminate  immediately
 849  * Preconditions:
 850  *      precond(cachedirp)
 851  *      precond(dirp)
 852  */
 853 
 854 int
 855 cache_check_dir(char *cachedirp, char *namep)
 856 {
 857         int xx;
 858         char buf[MAXPATHLEN];
 859         struct stat64 statinfo;
 860 
 861         /* see if path name is too long */
 862         xx = strlen(cachedirp) + strlen(namep) + 3;
 863         if (xx >= MAXPATHLEN) {
 864                 pr_err(gettext("Cache directory name %s is too long"),
 865                     cachedirp);
 866                 return (39);
 867         }
 868 
 869         /* make the pathname of the directory */
 870         sprintf(buf, "%s/%s", cachedirp, namep);
 871 
 872         /* get info on the directory */
 873         xx = lstat64(buf, &statinfo);
 874         if (xx == -1) {
 875                 /* if an error other than it does not exist */
 876                 if (errno != ENOENT) {
 877                         pr_err(gettext("Error on lstat(2) of %s: %s"),
 878                             buf, strerror(errno));
 879                         return (39);
 880                 }
 881 
 882                 /* make the directory */
 883                 xx = mkdir(buf, 0);
 884                 if (xx == -1) {
 885                         pr_err(gettext("Could not create directory %s"),
 886                             buf);
 887                         return (39);
 888                 }
 889                 pr_err(gettext("Created directory %s"), buf);
 890         }
 891 
 892         /* else see if really a directory */
 893         else if (!S_ISDIR(statinfo.st_mode)) {
 894                 /* get rid of the file */
 895                 xx = unlink(buf);
 896                 if (xx == -1) {
 897                         pr_err(gettext("Cannot remove %s: %s"), buf,
 898                             strerror(errno));
 899                         return (39);
 900                 }
 901 
 902                 /* make the directory */
 903                 xx = mkdir(buf, 0);
 904                 if (xx == -1) {
 905                         pr_err(gettext("Could not create directory %s"),
 906                             buf);
 907                         return (39);
 908                 }
 909                 pr_err(gettext("Created directory %s"), buf);
 910         }
 911 
 912         /* return success */
 913         return (0);
 914 }
 915 
 916 /*
 917  *
 918  *                      process_fsdir
 919  *
 920  * Description:
 921  *      Performs the necessary checking and repair on the
 922  *      specified file system cache directory.
 923  *      Calls res_addfile and res_addident as appropriate.
 924  * Arguments:
 925  *      cachedirp       name of cache directory
 926  *      namep           name of link file for the file system cache
 927  *      resp            res object for res_addfile and res_addident calls
 928  *      verbose         indicate level of verbosity for diagnostics
 929  * Returns:
 930  *               0      file system is okay and does not need checking
 931  *               1      problem unrelated to the file system
 932  *              32      file system is unmounted and needs checking
 933  *              33      file system is already mounted
 934  *              34      cannot stat device
 935  *              36      uncorrectable errors detected - terminate normally
 936  *              37      a signal was caught during processing
 937  *              39      uncorrectable errors detected - terminate  immediately
 938  * Preconditions:
 939  *      precond(cachedirp)
 940  *      precond(namep && is a sym link)
 941  *      precond(resp)
 942  */
 943 
 944 int
 945 process_fsdir(char *cachedirp, char *namep, res *resp, int verbose)
 946 {
 947         DIR *dp;
 948         struct dirent64 *dep;
 949         char linkpath[MAXPATHLEN];
 950         char dirpath[MAXPATHLEN];
 951         char attrpath[MAXPATHLEN];
 952         char buf[MAXPATHLEN];
 953         int xx;
 954         struct stat64 statinfo;
 955         char *atp = ATTRCACHE_NAME;
 956         int fd;
 957         ino64_t base;
 958         int local;
 959         char *strp;
 960         ino64_t fsid;
 961         int error = 0;
 962         int hashsize = 0;
 963         ENTRY hitem;
 964         ino64_t maxlocalfileno;
 965         cachefs_fsinfo_t fsinfo;
 966         time32_t btime;
 967 
 968         /* construct the path to the sym link */
 969         xx = strlen(cachedirp) + strlen(namep) + 3;
 970         if (xx >= MAXPATHLEN) {
 971                 pr_err(gettext("Pathname too long %s/%s"), cachedirp, namep);
 972                 error = 39;
 973                 goto out;
 974         }
 975         sprintf(linkpath, "%s/%s", cachedirp, namep);
 976 
 977         /* read the contents of the link */
 978         xx = readlink(linkpath, buf, sizeof (buf));
 979         if (xx == -1) {
 980                 pr_err(gettext("Unable to read link %s: %s"), linkpath,
 981                     strerror(errno));
 982                 error = 39;
 983                 goto out;
 984         }
 985         buf[xx] = '\0';
 986 
 987         /* do a one time check on lengths of files */
 988         xx = strlen(cachedirp) + strlen(buf) + 20 + 20;
 989         if (xx >= MAXPATHLEN) {
 990                 pr_err(gettext("Pathname too long %s/%s"), cachedirp, buf);
 991                 error = 39;
 992                 goto out;
 993         }
 994 
 995         /* construct the path to the directory */
 996         sprintf(dirpath, "%s/%s", cachedirp, buf);
 997 
 998         /* stat the directory */
 999         xx = lstat64(dirpath, &statinfo);
1000         if ((xx == -1) || (strtoull(buf, NULL, 16) != statinfo.st_ino)) {
1001                 if ((xx == -1) && (errno != ENOENT)) {
1002                         pr_err(gettext("Could not stat %s: %s"), dirpath,
1003                             strerror(errno));
1004                         error = 39;
1005                 } else
1006                         error = -1;
1007                 goto out;
1008         }
1009         fsid = statinfo.st_ino;
1010 
1011         /*
1012          * Check for a disconnect log(dlog) file and verify it.
1013          */
1014         xx = dlog_ck(dirpath, &maxlocalfileno);
1015         if (xx) {
1016                 error = -1;
1017                 goto out;
1018         }
1019 
1020         /* process the fsinfo file */
1021         sprintf(buf, "%s/%s", dirpath, CACHEFS_FSINFO);
1022         xx = process_fsinfo(buf, maxlocalfileno, &fsinfo, verbose);
1023         if (xx) {
1024                 error = -1;
1025                 pr_err(gettext("Cannot update fsinfo file %s"), buf);
1026                 goto out;
1027         }
1028 
1029         /* create the unmount file in the cachedir */
1030         sprintf(buf, "%s/%s", dirpath, CACHEFS_UNMNT_FILE);
1031         /* this file will be < 2GB */
1032         fd = open(buf, O_CREAT | O_RDWR, 0666);
1033         if (fd == -1) {
1034                 pr_err(gettext("Cannot create unmnt file %s: %s"), buf,
1035                     strerror(errno));
1036                 error = -1;
1037                 goto out;
1038         }
1039         btime = get_boottime();
1040         if (write(fd, &btime, sizeof (btime)) == -1) {
1041                 pr_err(gettext("Cannot write cachedir unmnt file %s: %s"), buf,
1042                     strerror(errno));
1043                 error = -1;
1044                 goto out;
1045         }
1046         close(fd);
1047 
1048         /* create the unmount file */
1049         sprintf(buf, "%s/%s", dirpath, CACHEFS_UNMNT_FILE);
1050         /* this file will be < 2GB */
1051         fd = open(buf, O_CREAT | O_RDWR, 0666);
1052         if (fd == -1) {
1053                 pr_err(gettext("Cannot create unmnt file %s: %s"), buf,
1054                     strerror(errno));
1055                 error = -1;
1056                 goto out;
1057         }
1058         close(fd);
1059 
1060         /* construct the name to the attrcache directory */
1061         sprintf(attrpath, "%s/%s", dirpath, atp);
1062 
1063         /* open the attrcache directory */
1064         if ((dp = opendir(attrpath)) == NULL) {
1065                 pr_err(gettext("Cannot open directory %s: %s"), attrpath,
1066                     strerror(errno));
1067                 error = -1;
1068                 goto out;
1069         }
1070 
1071         /* make one pass, counting how big to make the hash table */
1072         while (readdir64(dp) != NULL)
1073                 ++hashsize;
1074         if (hcreate(hashsize + 1000) == 0) {
1075                 pr_err(gettext("Cannot allocate heap space."));
1076                 (void) closedir(dp);
1077                 hashsize = 0;
1078                 error = 39;
1079                 goto out;
1080         }
1081         rewinddir(dp);
1082 
1083         /* loop reading the contents of the directory */
1084         while ((dep = readdir64(dp)) != NULL) {
1085                 /* ignore . and .. */
1086                 if ((strcmp(dep->d_name, ".") == 0) ||
1087                     (strcmp(dep->d_name, "..") == 0))
1088                         continue;
1089 
1090                 /* check for a reasonable name */
1091                 xx = strlen(dep->d_name);
1092                 if ((xx != 16) && (xx != 17)) {
1093                         /* bad file */
1094                         pr_err(gettext("Unknown file %s/%s"),
1095                                 attrpath, dep->d_name);
1096                         closedir(dp);
1097                         error = 39;
1098                         goto out;
1099                 }
1100 
1101                 /* derive the base number from the file name */
1102                 if (*(dep->d_name) == 'L') {
1103                         local = 1;
1104                         base = strtoull(dep->d_name + 1, &strp, 16);
1105                 } else {
1106                         local = 0;
1107                         base = strtoull(dep->d_name, &strp, 16);
1108                 }
1109                 if (*strp != '\0') {
1110                         /* bad file */
1111                         pr_err(gettext("Unknown file %s/%s"),
1112                                 attrpath, dep->d_name);
1113                         closedir(dp);
1114                         error = 39;
1115                         goto out;
1116                 }
1117 
1118                 /* process the file group */
1119                 error = process_fsgroup(dirpath, dep->d_name, resp,
1120                         base, fsinfo.fi_fgsize, fsid, local, verbose);
1121                 if (error) {
1122                         closedir(dp);
1123                         goto out;
1124                 }
1125         }
1126         closedir(dp);
1127 
1128         /* open the fscache directory */
1129         if ((dp = opendir(dirpath)) == NULL) {
1130                 pr_err(gettext("Cannot open directory %s: %s"), dirpath,
1131                     strerror(errno));
1132                 error = 39;
1133                 goto out;
1134         }
1135 
1136         /* loop reading the contents of the directory */
1137         while ((dep = readdir64(dp)) != NULL) {
1138                 /* ignore . and .. */
1139                 if ((strcmp(dep->d_name, ".") == 0) ||
1140                     (strcmp(dep->d_name, "..") == 0))
1141                         continue;
1142 
1143                 /* ignore cachefs special files */
1144                 xx = strncmp(dep->d_name, CACHEFS_PREFIX, CACHEFS_PREFIX_LEN);
1145                 if (xx == 0)
1146                         continue;
1147 
1148                 hitem.key = dep->d_name;
1149                 hitem.data = NULL;
1150                 if (hsearch(hitem, FIND) == NULL) {
1151                         sprintf(buf, "%s/%s", dirpath, dep->d_name);
1152                         if (verbose) {
1153                                 printf("Unreferenced dir %s\n", buf);
1154                         }
1155                         xx = nftw64(buf, tree_remove, 3, FLAGS_FTW);
1156                         if (xx != 0) {
1157                                 pr_err(gettext("Could not remove %s"), buf);
1158                                 error = 39;
1159                                 closedir(dp);
1160                                 goto out;
1161                         }
1162                 }
1163         }
1164         closedir(dp);
1165 
1166         /* add the info file to the resource */
1167         res_addfile(resp, 1);
1168 
1169         /* add the directory to the resources */
1170         res_addfile(resp, 1);
1171 
1172         /* add the sym link to the resources */
1173         res_addfile(resp, 1);
1174 
1175         /* change the mode on the directory to indicate we visited it */
1176         xx = chmod(dirpath, 0777);
1177         if (xx == -1) {
1178                 pr_err(gettext("Cannot chmod %s: %s"), dirpath,
1179                     strerror(errno));
1180                 error = 39;
1181                 goto out;
1182         }
1183 
1184 out:
1185         /* free up the heap allocated by the hash functions */
1186         if (hashsize != 0)
1187                 hdestroy();
1188 
1189         if (error == -1) {
1190                 /* remove the sym link */
1191                 xx = unlink(linkpath);
1192                 if (xx == -1) {
1193                         pr_err(gettext("Unable to remove %s: %s"), linkpath,
1194                             strerror(errno));
1195                         error = 39;
1196                 } else {
1197                         error = 0;
1198                 }
1199         }
1200 
1201         return (error);
1202 }
1203 
1204 /*
1205  * Processes and fixes up the fsinfo file.
1206  */
1207 int
1208 process_fsinfo(char *namep, ino64_t maxlocalfileno, cachefs_fsinfo_t *fsinfop,
1209     int verbose)
1210 {
1211         int fd;
1212         int error;
1213         cachefs_fsinfo_t fsinfo;
1214         int xx;
1215 
1216         /* open the info file; this file will be <2GB */
1217         fd = open(namep, O_RDWR);
1218         if (fd == -1) {
1219                 error = errno;
1220                 if (verbose)
1221                         pr_err(gettext("Could not open %s: %s"),
1222                             namep, strerror(errno));
1223                 if (error != ENOENT)
1224                         return (-1);
1225 
1226                 /* try to create the info file */
1227                 fd = open(namep, O_RDWR | O_CREAT, 0666);
1228                 if (fd == -1) {
1229                         if (verbose)
1230                                 pr_err(gettext("Could not create %s: %s"),
1231                                     namep, strerror(errno));
1232                         return (-1);
1233                 }
1234 
1235         }
1236 
1237         /* read the contents of the info file */
1238         xx = read(fd, &fsinfo, sizeof (fsinfo));
1239         if (xx != sizeof (fsinfo)) {
1240                 memset(&fsinfo, 0, sizeof (fsinfo));
1241         }
1242 
1243         /* fix up the fields as necessary */
1244         if (fsinfo.fi_popsize < DEF_POP_SIZE)
1245                 fsinfo.fi_popsize = DEF_POP_SIZE;
1246         if (fsinfo.fi_fgsize < DEF_FILEGRP_SIZE)
1247                 fsinfo.fi_fgsize = DEF_FILEGRP_SIZE;
1248         if (fsinfo.fi_localfileno < maxlocalfileno)
1249                 fsinfo.fi_localfileno = maxlocalfileno;
1250 
1251         /* write back the info to the file */
1252         if (lseek(fd, 0, SEEK_SET) == -1) {
1253                 if (verbose)
1254                         pr_err(gettext("Could not lseek %s: %s"),
1255                             namep, strerror(errno));
1256                 close(fd);
1257                 return (-1);
1258         }
1259         xx = write(fd, &fsinfo, sizeof (fsinfo));
1260         if (xx != sizeof (fsinfo)) {
1261                 if (verbose)
1262                         pr_err(gettext("Could not write %s: %s"),
1263                             namep, strerror(errno));
1264                 close(fd);
1265                 return (-1);
1266         }
1267 
1268         if (fsync(fd) == -1) {
1269                 pr_err(gettext("Could not sync %s: %s"),
1270                     namep, strerror(errno));
1271                 (void) close(fd);
1272                 return (-1);
1273         }
1274         (void) close(fd);
1275         *fsinfop = fsinfo;
1276         return (0);
1277 }
1278 
1279 /*
1280  *
1281  *                      process_fsgroup
1282  *
1283  * Description:
1284  *      Performs the necessary checking and repair on the
1285  *      specified file group directory.
1286  *      Calls res_addfile and res_addident as appropriate.
1287  * Arguments:
1288  *      dirpath pathname to fscache directory
1289  *      namep   name of fsgroup
1290  *      resp    res object for res_addfile and res_addident calls
1291  *      base    base offset for file numbers in this directory
1292  *      fgsize  size of the file groups
1293  *      fsid    file system id
1294  *      local   1 if fsgroup dir is a local dir
1295  *      verbose         indicate level of verbosity for diagnostics
1296  * Returns:
1297  *               0      file system is okay and does not need checking
1298  *               1      problem unrelated to the file system
1299  *              32      file system is unmounted and needs checking
1300  *              33      file system is already mounted
1301  *              34      cannot stat device
1302  *              36      uncorrectable errors detected - terminate normally
1303  *              37      a signal was caught during processing
1304  *              39      uncorrectable errors detected - terminate  immediately
1305  * Preconditions:
1306  *      precond(dirp)
1307  *      precond(namep)
1308  *      precond(resp)
1309  *      precond(fgsize > 0)
1310  */
1311 
1312 int
1313 process_fsgroup(char *dirp, char *namep, res *resp, ino64_t base, int fgsize,
1314     ino64_t fsid, int local, int verbose)
1315 {
1316         DIR *dp;
1317         struct dirent64 *dep;
1318         char buf[MAXPATHLEN];
1319         char attrfile[MAXPATHLEN];
1320         char attrdir[MAXPATHLEN];
1321         int xx;
1322         struct stat64 statinfo;
1323         char *atp = ATTRCACHE_NAME;
1324         void *addrp = MAP_FAILED;
1325         struct attrcache_header *ahp;
1326         struct attrcache_index *startp = NULL;
1327         struct attrcache_index *aip;
1328         uchar_t *bitp;
1329         int offlen;
1330         int bitlen;
1331         int fd;
1332         int offentry;
1333         int size;
1334         struct cachefs_metadata *metap;
1335         int index;
1336         char *strp;
1337         uint_t offset;
1338         int error = 0;
1339         ENTRY hitem;
1340         int nffs;
1341         int rlno;
1342         rl_entry_t ent;
1343         enum cachefs_rl_type which;
1344 
1345         /* construct the name to the attribute file and front file dir */
1346         sprintf(attrfile, "%s/%s/%s", dirp, atp, namep);
1347         sprintf(attrdir, "%s/%s", dirp, namep);
1348 
1349         /* get the size of the attribute file */
1350         xx = lstat64(attrfile, &statinfo);
1351         if (xx == -1) {
1352                 pr_err(gettext("Could not stat %s: %s"), attrfile,
1353                     strerror(errno));
1354                 error = 39;
1355                 goto out;
1356         }
1357 
1358         offlen = sizeof (struct attrcache_index) * fgsize;
1359         bitlen = (sizeof (uchar_t) * fgsize + 7) / 8;
1360         /* attrfile will be <2GB */
1361         size = (int)statinfo.st_size;
1362         offentry = sizeof (struct attrcache_header) + offlen + bitlen;
1363 
1364         /* if the attribute file is the wrong size */
1365         if (size < offentry) {
1366                 error = -1;
1367                 goto out;
1368         }
1369 
1370         /* open the attribute file */
1371         fd = open(attrfile, O_RDWR);
1372         if (fd == -1) {
1373                 pr_err(gettext("Could not open %s: %s"),
1374                         attrfile, strerror(errno));
1375                 error = 39;
1376                 goto out;
1377         }
1378 
1379         /* mmap the file into our address space */
1380         addrp = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1381         if (addrp == MAP_FAILED) {
1382                 pr_err(gettext("Could not map %s: %s"),
1383                         attrfile, strerror(errno));
1384                 close(fd);
1385                 error = 39;
1386                 goto out;
1387         }
1388         close(fd);
1389 
1390         /* set up pointers into mapped file */
1391         ahp = (struct attrcache_header *)addrp;
1392         startp = (struct attrcache_index *)(ahp + 1);
1393         bitp = (uchar_t *)((char *)startp + offlen);
1394 
1395         /* clear the bitmap */
1396         memset(bitp, 0, bitlen);
1397 
1398         /* fix number of allocated blocks value if necessary */
1399         xx = (size + MAXBSIZE - 1) / MAXBSIZE;
1400         if (xx != ahp->ach_nblks) {
1401                 if (verbose) {
1402                         pr_err(gettext("File %s size wrong, old %d new %d:"
1403                                 "corrected."),
1404                                 attrfile, ahp->ach_nblks, xx);
1405                 }
1406                 ahp->ach_nblks = xx;
1407         }
1408         ahp->ach_nffs = 0;
1409         nffs = 0;
1410 
1411         /* verify sanity of attribute file */
1412         ahp->ach_count = 0;
1413         for (index = 0; index < fgsize; index++) {
1414 
1415                 /* get next entry to work on */
1416                 aip = startp + index;
1417 
1418                 /* save offset to data */
1419                 offset = aip->ach_offset;
1420                 aip->ach_offset = 0;
1421 
1422                 /* if entry not in use */
1423                 if (aip->ach_written == 0)
1424                         continue;
1425                 aip->ach_written = 0;
1426 
1427                 /* if offset is out of range or invalid */
1428                 if ((offset < offentry) ||
1429                     ((size - sizeof (struct cachefs_metadata)) < offset) ||
1430                     (offset & 3)) {
1431                         if (verbose)
1432                                 pr_err(gettext("Offset %d invalid - index %d"),
1433                                     offset, index);
1434                         continue;
1435                 }
1436 
1437                 /* get pointer to meta data */
1438                 metap = (struct cachefs_metadata *)((char *)addrp + offset);
1439 
1440                 /* sanity check the meta data */
1441                 if ((metap->md_vattr.va_nodeid != (base + (ino64_t)index)) ||
1442                     ((metap->md_flags & (MD_FILE | MD_POPULATED)) ==
1443                     MD_POPULATED) ||
1444                     ((metap->md_flags & MD_FILE) && (metap->md_rlno == 0)) ||
1445                     (metap->md_rltype < CACHEFS_RL_START) ||
1446                     (metap->md_rltype > CACHEFS_RL_END)) {
1447                         if (verbose) {
1448                                 pr_err(gettext("Metadata corrupted %d"), index);
1449                         }
1450                         continue;
1451                 }
1452 
1453                 /* if there is a front file */
1454                 if (metap->md_flags & MD_FILE) {
1455                         /* make sure front file is still there */
1456                         if (local)
1457                                 sprintf(buf, "%s/L%016llx", attrdir,
1458                                     base + (ino64_t)index);
1459                         else
1460                                 sprintf(buf, "%s/%016llx", attrdir,
1461                                     base + (ino64_t)index);
1462                         if (access(buf, F_OK)) {
1463                                 if (verbose) {
1464                                         pr_err(gettext("File error %s %s"),
1465                                             buf, strerror(errno));
1466                                 }
1467                                 continue;
1468                         }
1469                         nffs++;
1470 
1471                         /* make sure default ACL directory holder is there */
1472                         if (metap->md_flags & MD_ACLDIR) {
1473                                 sprintf(buf, (local) ?
1474                                     "%s/L%016llx.d" : "%s/%016llx.d",
1475                                     attrdir, base + (ino64_t)index);
1476                                 if (access(buf, F_OK)) {
1477                                         if (verbose) {
1478                                                 pr_err(gettext(
1479                                                     "File error %s %s"),
1480                                                     buf, strerror(errno));
1481                                         }
1482                                         continue;
1483                                 }
1484                         }
1485                 }
1486 
1487                 /* if using a rl slot */
1488                 if (metap->md_rlno) {
1489                         /* make sure not on an unusable list */
1490                         if ((metap->md_rltype == CACHEFS_RL_NONE) ||
1491                             (metap->md_rltype == CACHEFS_RL_FREE)) {
1492                                 if (verbose) {
1493                                         pr_err(gettext("Bad list %d, %d"),
1494                                             metap->md_rltype, index);
1495                                 }
1496                                 continue;
1497                         }
1498 
1499                         /* move from the active to the gc list */
1500                         if (metap->md_rltype == CACHEFS_RL_ACTIVE)
1501                                 metap->md_rltype = CACHEFS_RL_GC;
1502 
1503                         /* move from the mf to the modified list */
1504                         if (metap->md_rltype == CACHEFS_RL_MF)
1505                                 metap->md_rltype = CACHEFS_RL_MODIFIED;
1506 
1507                         /* add to the resource file */
1508                         ent.rl_attrc = 0;
1509                         ent.rl_local = local;
1510                         ent.rl_fsid = fsid;
1511                         ent.rl_fileno = base + (ino64_t)index;
1512                         ent.rl_current = metap->md_rltype;
1513                         xx = res_addident(resp, metap->md_rlno, &ent,
1514                             metap->md_frontblks * MAXBSIZE,
1515                             (metap->md_flags & MD_FILE) ? 1 : 0);
1516                         if (xx == -1) {
1517                                 if (verbose) {
1518                                         pr_err(gettext(
1519                                             "File %s, bad rlno"), attrfile);
1520                                 }
1521                                 continue;
1522                         }
1523                         ahp->ach_nffs++;
1524                 }
1525 
1526                 /* mark entry as valid */
1527                 aip->ach_written = 1;
1528                 aip->ach_offset = offset;
1529 
1530                 /* set bitmap for this entry */
1531                 xx = (offset - offentry) / sizeof (struct cachefs_metadata);
1532                 bitp[xx/8] |= 1 << (xx % 8);
1533 
1534                 /* bump number of active entries */
1535                 ahp->ach_count += 1;
1536         }
1537 
1538         /* loop reading the contents of the front file directory */
1539         dp = opendir(attrdir);
1540         while (dp && ((dep = readdir64(dp)) != NULL)) {
1541                 int acldir;
1542 
1543                 /* ignore . and .. */
1544                 if ((strcmp(dep->d_name, ".") == 0) ||
1545                     (strcmp(dep->d_name, "..") == 0))
1546                         continue;
1547 
1548                 acldir = 0;
1549                 xx = strlen(dep->d_name);
1550                 /* check for valid ACL directory */
1551                 if ((xx > 2) && (strcmp(dep->d_name + xx - 2, ".d") == 0)) {
1552                         acldir = 1;
1553                 } else if ((xx != 16) && (xx != 17)) {
1554                         /*
1555                          * Bad file.
1556                          * Front file dir name is based on 64 bit inode number.
1557                          */
1558                         pr_err(gettext("Unknown file %s/%s"),
1559                                 attrdir, dep->d_name);
1560                         closedir(dp);
1561                         error = 39;
1562                         goto out;
1563                 }
1564 
1565                 sprintf(buf, "%s/%s", attrdir, dep->d_name);
1566 
1567                 /* determine index into file group */
1568                 if (*(dep->d_name) == 'L') {
1569                         index = (int)(strtoull(dep->d_name + 1, &strp,
1570                             16) - base);
1571                 } else {
1572                         index = (int)(strtoull(dep->d_name, &strp, 16) - base);
1573                 }
1574 
1575                 /* verify a valid file */
1576                 if (((! acldir) && (*strp != '\0')) ||
1577                     ((acldir) && (strcmp(strp, ".d") != 0)) ||
1578                     (index < 0) || (fgsize <= index) ||
1579                     (startp[index].ach_written == 0)) {
1580                         /* remove the file */
1581                         xx = file_remove(buf, NULL, verbose);
1582                         if (xx == -1) {
1583                                 error = 39;
1584                                 goto out;
1585                         }
1586                         continue;
1587                 }
1588 
1589                 /* verify file should be there */
1590                 aip = startp + index;
1591                 offset = aip->ach_offset;
1592                 metap = (struct cachefs_metadata *)((char *)addrp + offset);
1593                 if (((metap->md_flags & MD_FILE) == 0) ||
1594                     ((acldir) && ((metap->md_flags & MD_ACLDIR) == 0))) {
1595                         /* remove the file */
1596                         if (acldir)
1597                                 xx = rmdir(buf);
1598                         else
1599                                 xx = file_remove(buf, NULL, verbose);
1600                         if (xx == -1) {
1601                                 error = 39;
1602                                 goto out;
1603                         }
1604                         continue;
1605                 }
1606                 if (! acldir)
1607                         nffs--;
1608         }
1609 
1610         /* close the directory */
1611         if (dp)
1612                 closedir(dp);
1613 
1614         /* if we did not find the correct number of front files in the dir */
1615         rlno = ahp->ach_rlno;
1616         if (nffs != 0) {
1617                 if (verbose) {
1618                         pr_err(gettext("Front file mismatch %d in %s"),
1619                             nffs, attrdir);
1620                 }
1621                 error = -1;
1622                 goto out;
1623         }
1624 
1625         /* add the attrcache file to the resouce file */
1626         which = (ahp->ach_nffs == 0) ? CACHEFS_RL_GC : CACHEFS_RL_ATTRFILE;
1627         ahp->ach_rl_current = which;
1628         ent.rl_attrc = 1;
1629         ent.rl_local = local;
1630         ent.rl_fsid = fsid;
1631         ent.rl_fileno = base;
1632         ent.rl_current = which;
1633         error = res_addident(resp, rlno, &ent, size, 1);
1634         if (error == -1) {
1635                 if (verbose) {
1636                         pr_err(gettext("%s bad rlno %d\n"), attrfile, rlno);
1637                 }
1638                 goto out;
1639         } else if (ahp->ach_nffs > 0) {
1640                 /* add the directory to the resources */
1641                 res_addfile(resp, 1);
1642 
1643                 /* indicate that the file group directory is okay */
1644                 hitem.key = strdup(namep);
1645                 hitem.data = NULL;
1646                 if (hsearch(hitem, ENTER) == NULL) {
1647                         pr_err(gettext("Hash table full"));
1648                         error = 39;
1649                         goto out;
1650                 }
1651         }
1652 
1653 out:
1654         if (error == -1) {
1655                 if (startp) {
1656                         /* clear idents we created for this attrcache file */
1657                         for (index = 0; index < fgsize; index++) {
1658                                 aip = startp + index;
1659                                 if (aip->ach_written == 0)
1660                                         continue;
1661                                 metap = (struct cachefs_metadata *)((char *)
1662                                     addrp + aip->ach_offset);
1663                                 if (metap->md_rlno != 0) {
1664                                         /* clear the resource file idents */
1665                                         res_clearident(resp, metap->md_rlno,
1666                                             (metap->md_frontblks * MAXBSIZE),
1667                                             (metap->md_flags & MD_FILE) ? 1:0);
1668                                         if (verbose) {
1669                                                 pr_err(gettext("Removed %d"),
1670                                                         metap->md_rlno);
1671                                         }
1672                                 }
1673                         }
1674                 }
1675 
1676                 /* nuke the attrcache file */
1677                 xx = unlink(attrfile);
1678                 if (xx == -1) {
1679                         pr_err(gettext("Unable to remove %s"), attrfile);
1680                         error = 39;
1681                 } else {
1682                         error = 0;
1683                         if (verbose) {
1684                                 pr_err(gettext("Removed attrcache %s"),
1685                                         attrfile);
1686                         }
1687                 }
1688         }
1689 
1690         if (msync(addrp, size, MS_SYNC) == -1) {
1691                 pr_err(gettext("Unable to sync %s"), attrfile);
1692                 error = 39;
1693         }
1694 
1695         /* unmap the attribute file */
1696         if (addrp != MAP_FAILED)
1697                 munmap(addrp, size);
1698 
1699         return (error);
1700 }
1701 
1702 /*
1703  *
1704  *                      tree_remove
1705  *
1706  * Description:
1707  *      Called via the nftw64(3c) routine, this routine removes
1708  *      the specified file.
1709  * Arguments:
1710  *      namep   pathname to the file
1711  *      statp   stat info on the file
1712  *      type    ftw type information
1713  *      ftwp    pointer to additional ftw information
1714  * Returns:
1715  *      Returns 0 for success or -1 if an error occurs.
1716  * Preconditions:
1717  *      precond(namep)
1718  *      precond(statp)
1719  *      precond(ftwp)
1720  */
1721 
1722 int
1723 tree_remove(const char *namep, const struct stat64 *statp, int type,
1724     struct FTW *ftwp)
1725 {
1726         int xx;
1727 
1728         switch (type) {
1729         case FTW_D:
1730         case FTW_DP:
1731         case FTW_DNR:
1732                 xx = rmdir(namep);
1733                 if (xx != 0) {
1734                         pr_err(gettext("Could not remove directory %s: %s"),
1735                             namep, strerror(errno));
1736                         return (-1);
1737                 }
1738 #if 0
1739                 pr_err(gettext("Directory %s removed."), namep);
1740 #endif
1741                 break;
1742 
1743         default:
1744                 xx = file_remove(namep, statp, S_verbose);
1745 #if 0
1746                 pr_err(gettext("File %s removed."), namep);
1747 #endif
1748                 break;
1749         }
1750 
1751         /* return success */
1752         return (0);
1753 }
1754 
1755 /*
1756  *
1757  *                      file_remove
1758  *
1759  * Description:
1760  *      Removes the specified file.
1761  *      If the file is a local file or has been modified locally
1762  *      then it is moved to lost+found.
1763  *      Should only be called for non-directory files.
1764  * Arguments:
1765  *      namep   pathname to the file
1766  *      statp   stat info on the file or NULL
1767  *      verbose 1 means be verbose about what is being removed
1768  * Returns:
1769  *      Returns 0 for success or -1 if an error occurs.
1770  * Preconditions:
1771  *      precond(namep)
1772  */
1773 
1774 int
1775 file_remove(const char *namep, const struct stat64 *statp, int verbose)
1776 {
1777         int xx;
1778         int ii;
1779         struct stat64 statinfo;
1780         int dolf = 0;
1781         char newname[MAXPATHLEN * 2];
1782         char *strp;
1783 
1784         /* get stat info on the file if we were not passed it */
1785         if (statp == NULL) {
1786                 xx = stat64(namep, &statinfo);
1787                 if (xx) {
1788                         if (verbose) {
1789                                 pr_err(gettext("stat failed %s %d"),
1790                                     namep, errno);
1791                         }
1792                         return (-1);
1793                 }
1794                 statp = &statinfo;
1795         }
1796 
1797         /* ignore directories */
1798         if (S_ISDIR(statp->st_mode)) {
1799                 errno = EINVAL;
1800                 return (-1);
1801         }
1802 
1803         /* if a local file then move to lost+found */
1804         strp = strrchr(namep, '/');
1805         if (strp == NULL) {
1806                 errno = EINVAL;
1807                 return (-1);
1808         }
1809         strp++;
1810         if (*strp == 'L')
1811                 dolf = 1;
1812 
1813         /* if a modified file then move to lost+found */
1814         if ((statp->st_mode & S_IAMB) == 0766)
1815                 dolf = 1;
1816 
1817         /* if moving to lost+found */
1818         if (dolf) {
1819                 sprintf(newname, "%s/%s", S_lostfound, strp);
1820                 xx = stat64(newname, &statinfo);
1821                 for (ii = 1; ((ii < 1000) && (xx == 0)); ii++) {
1822                         sprintf(newname, "%s/%s_%d", S_lostfound, strp, ii);
1823                         xx = stat64(newname, &statinfo);
1824                 }
1825                 xx = rename(namep, newname);
1826                 if (xx) {
1827                         pr_err(gettext("Could not move file %s to %s: %s"),
1828                             namep, newname, strerror(errno));
1829                         exit(-1);
1830                 }
1831                 S_move_lostfound = 1;
1832                 return (0);
1833         }
1834 
1835         /* remove the file */
1836         xx = unlink(namep);
1837         if (xx == -1) {
1838                 pr_err(gettext("Could not remove file %s: %s"),
1839                     namep, strerror(errno));
1840         } else if (verbose) {
1841                 pr_err(gettext("Removed %s"), namep);
1842         }
1843 
1844         return (0);
1845 }
1846 
1847 void
1848 cache_backmnt_cleanup(char *cachedirp, char *backmnt_namep)
1849 {
1850         DIR *dirp;
1851         struct dirent *entp;
1852         char dirname[MAXPATHLEN * 2];
1853 
1854         /* open the directory */
1855         sprintf(dirname, "%s/%s", cachedirp, backmnt_namep);
1856         dirp = opendir(dirname);
1857         if (dirp == NULL)
1858                 return;
1859 
1860         /*
1861          * Try to remove everything in the directory with rmdir.
1862          * Should only be empty directories in here at this point.
1863          * If not, do not worry about it.
1864          */
1865         for (;;) {
1866                 /* get the next dir entry */
1867                 entp = readdir(dirp);
1868                 if (entp == NULL)
1869                         break;
1870 
1871                 /*
1872                  * Try and remove the directory.
1873                  * This will fail if there is anything in the dir,
1874                  * like a mounted file system.
1875                  */
1876                 rmdir(entp->d_name);
1877         }
1878         closedir(dirp);
1879 }