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