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