xref: /titanic_44/usr/src/cmd/fs.d/cachefs/fsck/fsck.c (revision 95efa359b507db290a2484b8f615822b1e06096f)
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 }
1880