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 }