xref: /onnv-gate/usr/src/cmd/fs.d/ufs/fsck/main.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
8*0Sstevel@tonic-gate 
9*0Sstevel@tonic-gate 
10*0Sstevel@tonic-gate /*
11*0Sstevel@tonic-gate  * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
12*0Sstevel@tonic-gate  * All rights reserved.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms are permitted
15*0Sstevel@tonic-gate  * provided that: (1) source distributions retain this entire copyright
16*0Sstevel@tonic-gate  * notice and comment, and (2) distributions including binaries display
17*0Sstevel@tonic-gate  * the following acknowledgement:  ``This product includes software
18*0Sstevel@tonic-gate  * developed by the University of California, Berkeley and its contributors''
19*0Sstevel@tonic-gate  * in the documentation or other materials provided with the distribution
20*0Sstevel@tonic-gate  * and in all advertising materials mentioning features or use of this
21*0Sstevel@tonic-gate  * software. Neither the name of the University nor the names of its
22*0Sstevel@tonic-gate  * contributors may be used to endorse or promote products derived
23*0Sstevel@tonic-gate  * from this software without specific prior written permission.
24*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
25*0Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
26*0Sstevel@tonic-gate  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27*0Sstevel@tonic-gate  */
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #include <stdio.h>
32*0Sstevel@tonic-gate #include <sys/param.h>
33*0Sstevel@tonic-gate #include <sys/types.h>
34*0Sstevel@tonic-gate #include <sys/int_types.h>
35*0Sstevel@tonic-gate #include <sys/sysmacros.h>
36*0Sstevel@tonic-gate #include <sys/mntent.h>
37*0Sstevel@tonic-gate 
38*0Sstevel@tonic-gate #define	bcopy(f, t, n)    memcpy(t, f, n)
39*0Sstevel@tonic-gate #define	bzero(s, n)	memset(s, 0, n)
40*0Sstevel@tonic-gate #define	bcmp(s, d, n)	memcmp(s, d, n)
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate #define	index(s, r)	strchr(s, r)
43*0Sstevel@tonic-gate #define	rindex(s, r)	strrchr(s, r)
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #include <sys/fs/ufs_fs.h>
46*0Sstevel@tonic-gate #include <sys/vnode.h>
47*0Sstevel@tonic-gate #include <sys/fs/ufs_inode.h>
48*0Sstevel@tonic-gate #include <sys/stat.h>
49*0Sstevel@tonic-gate #include <sys/wait.h>
50*0Sstevel@tonic-gate #include <sys/mnttab.h>
51*0Sstevel@tonic-gate #include <sys/signal.h>
52*0Sstevel@tonic-gate #include <string.h>
53*0Sstevel@tonic-gate #include <ctype.h>	/* use isdigit macro rather than 4.1 libc routine */
54*0Sstevel@tonic-gate #include "fsck.h"
55*0Sstevel@tonic-gate #include <sys/vfstab.h>
56*0Sstevel@tonic-gate #include <sys/ustat.h>
57*0Sstevel@tonic-gate #include <sys/statvfs.h>
58*0Sstevel@tonic-gate #include <errno.h>
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate int	mflag = 0;		/* sanity check only */
61*0Sstevel@tonic-gate char	hotroot;
62*0Sstevel@tonic-gate 
63*0Sstevel@tonic-gate uint_t largefile_count = 0;	/* global largefile counter */
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate extern int	optind;
66*0Sstevel@tonic-gate extern char	*optarg;
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate char	*mntopt();
69*0Sstevel@tonic-gate char	*malloc();
70*0Sstevel@tonic-gate void	catch(), catchquit(), voidquit();
71*0Sstevel@tonic-gate int	returntosingle;
72*0Sstevel@tonic-gate void	checkfilesys();
73*0Sstevel@tonic-gate void	update_lf();
74*0Sstevel@tonic-gate void	main();
75*0Sstevel@tonic-gate void	check_sanity();
76*0Sstevel@tonic-gate void	usage();
77*0Sstevel@tonic-gate struct dinode *getnextinode();
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate char *subopts [] = {
80*0Sstevel@tonic-gate #define	PREEN		0
81*0Sstevel@tonic-gate 	"p",
82*0Sstevel@tonic-gate #define	BLOCK		1
83*0Sstevel@tonic-gate 	"b",
84*0Sstevel@tonic-gate #define	DEBUG		2
85*0Sstevel@tonic-gate 	"d",
86*0Sstevel@tonic-gate #define	READ_ONLY	3
87*0Sstevel@tonic-gate 	"r",
88*0Sstevel@tonic-gate #define	ONLY_WRITES	4
89*0Sstevel@tonic-gate 	"w",
90*0Sstevel@tonic-gate #define	CONVERT		5	/* setup.c convert between fffs and ffs */
91*0Sstevel@tonic-gate 	"c",
92*0Sstevel@tonic-gate #define	FORCE		6	/* force checking, even if clean */
93*0Sstevel@tonic-gate 	"f",
94*0Sstevel@tonic-gate 	NULL
95*0Sstevel@tonic-gate };
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate char **sargv;
98*0Sstevel@tonic-gate void
99*0Sstevel@tonic-gate main(argc, argv)
100*0Sstevel@tonic-gate 	int	argc;
101*0Sstevel@tonic-gate 	char	*argv[];
102*0Sstevel@tonic-gate {
103*0Sstevel@tonic-gate 	int	c;
104*0Sstevel@tonic-gate 	char	*suboptions,	*value;
105*0Sstevel@tonic-gate 	int	suboption;
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	/*
108*0Sstevel@tonic-gate 	 * Save argv pointer to be used if a hole in a directory's block list
109*0Sstevel@tonic-gate 	 * is found.
110*0Sstevel@tonic-gate 	 */
111*0Sstevel@tonic-gate 	sargv = argv;
112*0Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "mnNo:VyYz")) != EOF) {
113*0Sstevel@tonic-gate 		switch (c) {
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate 		case 'm':
116*0Sstevel@tonic-gate 			mflag++;
117*0Sstevel@tonic-gate 			break;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate 		case 'n':	/* default no answer flag */
120*0Sstevel@tonic-gate 		case 'N':
121*0Sstevel@tonic-gate 			nflag++;
122*0Sstevel@tonic-gate 			yflag = 0;
123*0Sstevel@tonic-gate 			break;
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate 		case 'o':
126*0Sstevel@tonic-gate 			/*
127*0Sstevel@tonic-gate 			 * ufs specific options.
128*0Sstevel@tonic-gate 			 */
129*0Sstevel@tonic-gate 			suboptions = optarg;
130*0Sstevel@tonic-gate 			while (*suboptions != '\0') {
131*0Sstevel@tonic-gate 				switch ((suboption = getsubopt(&suboptions,
132*0Sstevel@tonic-gate 							subopts, &value))) {
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 				case PREEN:
135*0Sstevel@tonic-gate 					preen++;
136*0Sstevel@tonic-gate 					break;
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 				case BLOCK:
139*0Sstevel@tonic-gate 					if (value == NULL) {
140*0Sstevel@tonic-gate 						usage();
141*0Sstevel@tonic-gate 					} else {
142*0Sstevel@tonic-gate 						bflag = atoi(value);
143*0Sstevel@tonic-gate 					}
144*0Sstevel@tonic-gate 				printf("Alternate super block location: %d.\n",
145*0Sstevel@tonic-gate 					    bflag);
146*0Sstevel@tonic-gate 					break;
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate 				case CONVERT:
149*0Sstevel@tonic-gate 					cvtflag++;
150*0Sstevel@tonic-gate 					break;
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 				case DEBUG:
153*0Sstevel@tonic-gate 					debug++;
154*0Sstevel@tonic-gate 					break;
155*0Sstevel@tonic-gate 
156*0Sstevel@tonic-gate 				case READ_ONLY:
157*0Sstevel@tonic-gate 					break;
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 				case ONLY_WRITES:
160*0Sstevel@tonic-gate 					/* check only writable filesystems */
161*0Sstevel@tonic-gate 					wflag++;
162*0Sstevel@tonic-gate 					break;
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 				case FORCE:
165*0Sstevel@tonic-gate 					fflag++;
166*0Sstevel@tonic-gate 					break;
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 				default:
169*0Sstevel@tonic-gate 					usage();
170*0Sstevel@tonic-gate 				}
171*0Sstevel@tonic-gate 			}
172*0Sstevel@tonic-gate 			break;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 		case 'V':
175*0Sstevel@tonic-gate 			{
176*0Sstevel@tonic-gate 				int	opt_count;
177*0Sstevel@tonic-gate 				char	*opt_text;
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate 				(void) fprintf(stdout, "fsck -F ufs ");
180*0Sstevel@tonic-gate 				for (opt_count = 1; opt_count < argc;
181*0Sstevel@tonic-gate 								opt_count++) {
182*0Sstevel@tonic-gate 					opt_text = argv[opt_count];
183*0Sstevel@tonic-gate 					if (opt_text)
184*0Sstevel@tonic-gate 						(void) fprintf(stdout, " %s ",
185*0Sstevel@tonic-gate 								opt_text);
186*0Sstevel@tonic-gate 				}
187*0Sstevel@tonic-gate 				(void) fprintf(stdout, "\n");
188*0Sstevel@tonic-gate 			}
189*0Sstevel@tonic-gate 			break;
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 		case 'y':	/* default yes answer flag */
192*0Sstevel@tonic-gate 		case 'Y':
193*0Sstevel@tonic-gate 			yflag++;
194*0Sstevel@tonic-gate 			nflag = 0;
195*0Sstevel@tonic-gate 			break;
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 		case '?':
198*0Sstevel@tonic-gate 			usage();
199*0Sstevel@tonic-gate 		}
200*0Sstevel@tonic-gate 	}
201*0Sstevel@tonic-gate 	argc -= optind;
202*0Sstevel@tonic-gate 	argv = &argv[optind];
203*0Sstevel@tonic-gate 	rflag++; /* check raw devices */
204*0Sstevel@tonic-gate 	if (signal(SIGINT, SIG_IGN) != (int)SIG_IGN)
205*0Sstevel@tonic-gate 		(void) signal(SIGINT, catch);
206*0Sstevel@tonic-gate 	if (preen)
207*0Sstevel@tonic-gate 		(void) signal(SIGQUIT, catchquit);
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	if (argc) {
210*0Sstevel@tonic-gate 		while (argc-- > 0) {
211*0Sstevel@tonic-gate 			if (wflag && !writable(*argv)) {
212*0Sstevel@tonic-gate 				(void) fprintf(stderr, "not writeable '%s'\n",
213*0Sstevel@tonic-gate 									*argv);
214*0Sstevel@tonic-gate 				argv++;
215*0Sstevel@tonic-gate 			} else
216*0Sstevel@tonic-gate 				checkfilesys(*argv++);
217*0Sstevel@tonic-gate 		}
218*0Sstevel@tonic-gate 		exit(exitstat);
219*0Sstevel@tonic-gate 	}
220*0Sstevel@tonic-gate }
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate void
224*0Sstevel@tonic-gate checkfilesys(filesys)
225*0Sstevel@tonic-gate 	char *filesys;
226*0Sstevel@tonic-gate {
227*0Sstevel@tonic-gate 	daddr32_t n_ffree, n_bfree;
228*0Sstevel@tonic-gate 	struct dups *dp;
229*0Sstevel@tonic-gate 	struct zlncnt *zlnp;
230*0Sstevel@tonic-gate 	char *devstr;
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 	mountfd = -1;
233*0Sstevel@tonic-gate 	hotroot = 0;
234*0Sstevel@tonic-gate 	mountedfs = 0;
235*0Sstevel@tonic-gate 	iscorrupt = 1;
236*0Sstevel@tonic-gate 	isconvert = 0;
237*0Sstevel@tonic-gate 	ismdd = 0;
238*0Sstevel@tonic-gate 	islog = 0;
239*0Sstevel@tonic-gate 	islogok = 0;
240*0Sstevel@tonic-gate 	dirholes = 0;
241*0Sstevel@tonic-gate 	needs_reclaim = 0;
242*0Sstevel@tonic-gate 	errorlocked = is_errorlocked(filesys);
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	if ((devstr = setup(filesys)) == 0) {
245*0Sstevel@tonic-gate 		if (iscorrupt == 0)
246*0Sstevel@tonic-gate 			return;
247*0Sstevel@tonic-gate 		if (preen)
248*0Sstevel@tonic-gate 			pfatal("CAN'T CHECK FILE SYSTEM.");
249*0Sstevel@tonic-gate 		if ((exitstat == 0) && (mflag))
250*0Sstevel@tonic-gate 			exitstat = 32;
251*0Sstevel@tonic-gate 		exit(exitstat);
252*0Sstevel@tonic-gate 	}
253*0Sstevel@tonic-gate 	else
254*0Sstevel@tonic-gate 		devname = devstr;
255*0Sstevel@tonic-gate 	if (mflag)
256*0Sstevel@tonic-gate 		check_sanity(filesys);	/* this never returns */
257*0Sstevel@tonic-gate 	if (debug)
258*0Sstevel@tonic-gate 		printclean();
259*0Sstevel@tonic-gate 	iscorrupt = 0;
260*0Sstevel@tonic-gate 	/*
261*0Sstevel@tonic-gate 	 * 1: scan inodes tallying blocks used
262*0Sstevel@tonic-gate 	 */
263*0Sstevel@tonic-gate 	if (preen == 0) {
264*0Sstevel@tonic-gate 		if (mountedfs)
265*0Sstevel@tonic-gate 			printf("** Currently Mounted on %s\n", sblock.fs_fsmnt);
266*0Sstevel@tonic-gate 		else
267*0Sstevel@tonic-gate 			printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
268*0Sstevel@tonic-gate 		if (mflag) {
269*0Sstevel@tonic-gate 			printf("** Phase 1 - Sanity Check only\n");
270*0Sstevel@tonic-gate 			return;
271*0Sstevel@tonic-gate 		} else {
272*0Sstevel@tonic-gate 			printf("** Phase 1 - Check Blocks and Sizes\n");
273*0Sstevel@tonic-gate 		}
274*0Sstevel@tonic-gate 	}
275*0Sstevel@tonic-gate 	pass1();
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	/*
278*0Sstevel@tonic-gate 	 * 1b: locate first references to duplicates, if any
279*0Sstevel@tonic-gate 	 */
280*0Sstevel@tonic-gate 	if (duplist) {
281*0Sstevel@tonic-gate 		if (preen)
282*0Sstevel@tonic-gate 			pfatal("INTERNAL ERROR: dups with -p");
283*0Sstevel@tonic-gate 		printf("** Phase 1b - Rescan For More DUPS\n");
284*0Sstevel@tonic-gate 		pass1b();
285*0Sstevel@tonic-gate 	}
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	/*
288*0Sstevel@tonic-gate 	 * 2: traverse directories from root to mark all connected directories
289*0Sstevel@tonic-gate 	 */
290*0Sstevel@tonic-gate 	if (preen == 0) {
291*0Sstevel@tonic-gate 		printf("** Phase 2 - Check Pathnames\n");
292*0Sstevel@tonic-gate 	}
293*0Sstevel@tonic-gate 	pass2();
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate 	/*
296*0Sstevel@tonic-gate 	 * 3: scan inodes looking for disconnected directories
297*0Sstevel@tonic-gate 	 */
298*0Sstevel@tonic-gate 	if (preen == 0) {
299*0Sstevel@tonic-gate 		printf("** Phase 3 - Check Connectivity\n");
300*0Sstevel@tonic-gate 	}
301*0Sstevel@tonic-gate 	pass3();
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 	/*
304*0Sstevel@tonic-gate 	 * 3b: check acls
305*0Sstevel@tonic-gate 	 */
306*0Sstevel@tonic-gate 	pass3b();
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	/*
309*0Sstevel@tonic-gate 	 * 4: scan inodes looking for disconnected files; check reference counts
310*0Sstevel@tonic-gate 	 */
311*0Sstevel@tonic-gate 	if (preen == 0) {
312*0Sstevel@tonic-gate 		printf("** Phase 4 - Check Reference Counts\n");
313*0Sstevel@tonic-gate 	}
314*0Sstevel@tonic-gate 	pass4();
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 	/*
317*0Sstevel@tonic-gate 	 * 5: check and repair resource counts in cylinder groups
318*0Sstevel@tonic-gate 	 */
319*0Sstevel@tonic-gate 	if (preen == 0) {
320*0Sstevel@tonic-gate 		printf("** Phase 5 - Check Cyl groups\n");
321*0Sstevel@tonic-gate 	}
322*0Sstevel@tonic-gate 	pass5();
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	updateclean();
325*0Sstevel@tonic-gate 	if (debug)
326*0Sstevel@tonic-gate 		printclean();
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	/*
329*0Sstevel@tonic-gate 	 * print out summary statistics
330*0Sstevel@tonic-gate 	 */
331*0Sstevel@tonic-gate 	n_ffree = sblock.fs_cstotal.cs_nffree;
332*0Sstevel@tonic-gate 	n_bfree = sblock.fs_cstotal.cs_nbfree;
333*0Sstevel@tonic-gate 	pwarn("%d files, %d used, %d free ",
334*0Sstevel@tonic-gate 	    n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
335*0Sstevel@tonic-gate 	if (preen)
336*0Sstevel@tonic-gate 		printf("\n");
337*0Sstevel@tonic-gate 	pwarn("(%d frags, %d blocks, %.1f%% fragmentation)\n",
338*0Sstevel@tonic-gate 	    n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize);
339*0Sstevel@tonic-gate 	if (debug &&
340*0Sstevel@tonic-gate 	    (n_files -= maxino - UFSROOTINO - sblock.fs_cstotal.cs_nifree))
341*0Sstevel@tonic-gate 		printf("%d files missing\n", n_files);
342*0Sstevel@tonic-gate 	if (debug) {
343*0Sstevel@tonic-gate 		n_blks += sblock.fs_ncg *
344*0Sstevel@tonic-gate 			(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
345*0Sstevel@tonic-gate 		n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
346*0Sstevel@tonic-gate 		n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
347*0Sstevel@tonic-gate 		if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
348*0Sstevel@tonic-gate 			printf("%d blocks missing\n", n_blks);
349*0Sstevel@tonic-gate 		if (duplist != NULL) {
350*0Sstevel@tonic-gate 			printf("The following duplicate blocks remain:");
351*0Sstevel@tonic-gate 			for (dp = duplist; dp; dp = dp->next)
352*0Sstevel@tonic-gate 				printf(" %d,", dp->dup);
353*0Sstevel@tonic-gate 			printf("\n");
354*0Sstevel@tonic-gate 		}
355*0Sstevel@tonic-gate 		if (zlnhead != NULL) {
356*0Sstevel@tonic-gate 			printf("The following zero link count inodes remain:");
357*0Sstevel@tonic-gate 			for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
358*0Sstevel@tonic-gate 				printf(" %d,", zlnp->zlncnt);
359*0Sstevel@tonic-gate 			printf("\n");
360*0Sstevel@tonic-gate 		}
361*0Sstevel@tonic-gate 	}
362*0Sstevel@tonic-gate 	zlnhead = (struct zlncnt *)0;
363*0Sstevel@tonic-gate 	duplist = muldup = (struct dups *)0;
364*0Sstevel@tonic-gate 	inocleanup();
365*0Sstevel@tonic-gate 	ckfini();
366*0Sstevel@tonic-gate 	free(blockmap);
367*0Sstevel@tonic-gate 	free(statemap);
368*0Sstevel@tonic-gate 	free((char *)lncntp);
369*0Sstevel@tonic-gate 	lncntp = NULL;
370*0Sstevel@tonic-gate 	blockmap = statemap = NULL;
371*0Sstevel@tonic-gate 	if (iscorrupt)
372*0Sstevel@tonic-gate 		exitstat = 36;
373*0Sstevel@tonic-gate 	if (!fsmodified)
374*0Sstevel@tonic-gate 		return;
375*0Sstevel@tonic-gate 	if (!preen)
376*0Sstevel@tonic-gate 		printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	if (dirholes) {
379*0Sstevel@tonic-gate 
380*0Sstevel@tonic-gate 		if (preen) {
381*0Sstevel@tonic-gate 			printf("\nFixed directory holes, Re-checking %s\n",
382*0Sstevel@tonic-gate 				devname);
383*0Sstevel@tonic-gate 			execv("/usr/sbin/fsck", sargv);
384*0Sstevel@tonic-gate 			printf("Exec failed %s\n", strerror(errno));
385*0Sstevel@tonic-gate 		}
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 		printf("\nFixed directories with holes, Run fsck once again\n");
388*0Sstevel@tonic-gate 		exitstat = 36;
389*0Sstevel@tonic-gate 	} else {
390*0Sstevel@tonic-gate 		if ((mountedfs && !errorlocked) || hotroot) {
391*0Sstevel@tonic-gate 			exitstat = 40;
392*0Sstevel@tonic-gate 		}
393*0Sstevel@tonic-gate 	}
394*0Sstevel@tonic-gate }
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 
397*0Sstevel@tonic-gate /*
398*0Sstevel@tonic-gate  * exit 0 - file system is unmounted and okay
399*0Sstevel@tonic-gate  * exit 32 - file system is unmounted and needs checking
400*0Sstevel@tonic-gate  * exit 33 - file system is mounted
401*0Sstevel@tonic-gate  *          for root file system
402*0Sstevel@tonic-gate  * exit 34 - cannot stat device
403*0Sstevel@tonic-gate  */
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate void
406*0Sstevel@tonic-gate check_sanity(filename)
407*0Sstevel@tonic-gate char	*filename;
408*0Sstevel@tonic-gate {
409*0Sstevel@tonic-gate 	struct stat64 stbd, stbr;
410*0Sstevel@tonic-gate 	struct ustat usb;
411*0Sstevel@tonic-gate 	char *devname;
412*0Sstevel@tonic-gate 	char vfsfilename[MAXPATHLEN];
413*0Sstevel@tonic-gate 	struct vfstab vfsbuf;
414*0Sstevel@tonic-gate 	FILE *vfstab;
415*0Sstevel@tonic-gate 	struct statvfs vfs_stat;
416*0Sstevel@tonic-gate 	int is_root = 0;
417*0Sstevel@tonic-gate 	int is_usr = 0;
418*0Sstevel@tonic-gate 	int is_block = 0;
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	if (stat64(filename, &stbd) < 0) {
421*0Sstevel@tonic-gate 		fprintf(stderr,
422*0Sstevel@tonic-gate 		"ufs fsck: sanity check failed : cannot stat %s\n", filename);
423*0Sstevel@tonic-gate 		exit(34);
424*0Sstevel@tonic-gate 	}
425*0Sstevel@tonic-gate 
426*0Sstevel@tonic-gate 	if ((stbd.st_mode & S_IFMT) == S_IFBLK)
427*0Sstevel@tonic-gate 		is_block = 1;
428*0Sstevel@tonic-gate 	else if ((stbd.st_mode & S_IFMT) == S_IFCHR)
429*0Sstevel@tonic-gate 		is_block = 0;
430*0Sstevel@tonic-gate 	else {
431*0Sstevel@tonic-gate 		fprintf(stderr,
432*0Sstevel@tonic-gate 	"ufs fsck: sanity check failed: %s not block or character device\n",
433*0Sstevel@tonic-gate 		filename);
434*0Sstevel@tonic-gate 		exit(34);
435*0Sstevel@tonic-gate 	}
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	/*
438*0Sstevel@tonic-gate 	 * Determine if this is the root file system via vfstab. Give up
439*0Sstevel@tonic-gate 	 * silently on failures. The whole point of this is not to care
440*0Sstevel@tonic-gate 	 * if the root file system is already mounted.
441*0Sstevel@tonic-gate 	 *
442*0Sstevel@tonic-gate 	 * XXX - similar for /usr. This should be fixed to simply return
443*0Sstevel@tonic-gate 	 * a new code indicating, mounted and needs to be checked.
444*0Sstevel@tonic-gate 	 */
445*0Sstevel@tonic-gate 	if ((vfstab = fopen(VFSTAB, "r")) != 0) {
446*0Sstevel@tonic-gate 		if (getvfsfile(vfstab, &vfsbuf, "/") == 0) {
447*0Sstevel@tonic-gate 			if (is_block)
448*0Sstevel@tonic-gate 				devname = vfsbuf.vfs_special;
449*0Sstevel@tonic-gate 			else
450*0Sstevel@tonic-gate 				devname = vfsbuf.vfs_fsckdev;
451*0Sstevel@tonic-gate 			if (stat64(devname, &stbr) == 0)
452*0Sstevel@tonic-gate 				if (stbr.st_rdev == stbd.st_rdev)
453*0Sstevel@tonic-gate 					is_root = 1;
454*0Sstevel@tonic-gate 		}
455*0Sstevel@tonic-gate 		if (getvfsfile(vfstab, &vfsbuf, "/usr") == 0) {
456*0Sstevel@tonic-gate 			if (is_block)
457*0Sstevel@tonic-gate 				devname = vfsbuf.vfs_special;
458*0Sstevel@tonic-gate 			else
459*0Sstevel@tonic-gate 				devname = vfsbuf.vfs_fsckdev;
460*0Sstevel@tonic-gate 			if (stat64(devname, &stbr) == 0)
461*0Sstevel@tonic-gate 				if (stbr.st_rdev == stbd.st_rdev)
462*0Sstevel@tonic-gate 					is_usr = 1;
463*0Sstevel@tonic-gate 		}
464*0Sstevel@tonic-gate 	}
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	/*
468*0Sstevel@tonic-gate 	 * XXX - only works if filename is a block device or if
469*0Sstevel@tonic-gate 	 * character and block device has the same dev_t value
470*0Sstevel@tonic-gate 	 */
471*0Sstevel@tonic-gate 	if (is_root == 0 && is_usr == 0 && ustat(stbd.st_rdev, &usb) == 0) {
472*0Sstevel@tonic-gate 		fprintf(stderr, "ufs fsck: sanity check: %s already mounted\n",
473*0Sstevel@tonic-gate 		filename);
474*0Sstevel@tonic-gate 		exit(33);
475*0Sstevel@tonic-gate 	}
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 	if (is_root || is_usr) {
478*0Sstevel@tonic-gate 		if (is_root)
479*0Sstevel@tonic-gate 			strcpy(vfsfilename, "/");
480*0Sstevel@tonic-gate 		else
481*0Sstevel@tonic-gate 			strcpy(vfsfilename, "/usr");
482*0Sstevel@tonic-gate 		if (statvfs(vfsfilename, &vfs_stat) != 0) {
483*0Sstevel@tonic-gate 			fprintf(stderr,
484*0Sstevel@tonic-gate 				"ufs fsck: Cannot stat %s\n",
485*0Sstevel@tonic-gate 				vfsfilename);
486*0Sstevel@tonic-gate 			exit(34);
487*0Sstevel@tonic-gate 		}
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 		if (!(vfs_stat.f_flag & ST_RDONLY)) {
490*0Sstevel@tonic-gate 			/*
491*0Sstevel@tonic-gate 			 * The file system is mounted read/write
492*0Sstevel@tonic-gate 			 * We need to exit saying that / or /usr is
493*0Sstevel@tonic-gate 			 * already mounted read/write. If it's only
494*0Sstevel@tonic-gate 			 * mounted readonly, we can continue.
495*0Sstevel@tonic-gate 			 */
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 			fprintf(stderr,
498*0Sstevel@tonic-gate 				"ufs fsck: sanity check:"
499*0Sstevel@tonic-gate 				"%s already mounted read/write\n",
500*0Sstevel@tonic-gate 				filename);
501*0Sstevel@tonic-gate 			exit(33);
502*0Sstevel@tonic-gate 		}
503*0Sstevel@tonic-gate 	}
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	/*
506*0Sstevel@tonic-gate 	 * We mount the ufs root file system read-only first.  After fsck
507*0Sstevel@tonic-gate 	 * runs, we remount the root as read-write.  Therefore, we no longer
508*0Sstevel@tonic-gate 	 * check for different values for fs_state between the root file
509*0Sstevel@tonic-gate 	 * system and the rest of file systems.
510*0Sstevel@tonic-gate 	 */
511*0Sstevel@tonic-gate 	if (islog && !islogok) {
512*0Sstevel@tonic-gate 		fprintf(stderr, "ufs fsck: sanity check: %s needs checking\n",
513*0Sstevel@tonic-gate 			filename);
514*0Sstevel@tonic-gate 		exit(32);
515*0Sstevel@tonic-gate 	}
516*0Sstevel@tonic-gate 	if ((sblock.fs_state + (long)sblock.fs_time == FSOKAY) &&
517*0Sstevel@tonic-gate 		(sblock.fs_clean == FSCLEAN || sblock.fs_clean == FSSTABLE ||
518*0Sstevel@tonic-gate 		(sblock.fs_clean == FSLOG && islog))) {
519*0Sstevel@tonic-gate 		fprintf(stderr, "ufs fsck: sanity check: %s okay\n", filename);
520*0Sstevel@tonic-gate 	} else {
521*0Sstevel@tonic-gate 		fprintf(stderr, "ufs fsck: sanity check: %s needs checking\n",
522*0Sstevel@tonic-gate 			filename);
523*0Sstevel@tonic-gate 		exit(32);
524*0Sstevel@tonic-gate 	}
525*0Sstevel@tonic-gate 	exit(0);
526*0Sstevel@tonic-gate }
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate char *
529*0Sstevel@tonic-gate unrawname(name)
530*0Sstevel@tonic-gate 	char *name;
531*0Sstevel@tonic-gate {
532*0Sstevel@tonic-gate 	char *dp;
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	extern char *getfullblkname();
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 	if ((dp = getfullblkname(name)) == NULL)
537*0Sstevel@tonic-gate 		return ("");
538*0Sstevel@tonic-gate 	return (dp);
539*0Sstevel@tonic-gate }
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate char *
542*0Sstevel@tonic-gate rawname(name)
543*0Sstevel@tonic-gate 	char *name;
544*0Sstevel@tonic-gate {
545*0Sstevel@tonic-gate 	char *dp;
546*0Sstevel@tonic-gate 
547*0Sstevel@tonic-gate 	extern char *getfullrawname();
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 	if ((dp = getfullrawname(name)) == NULL)
550*0Sstevel@tonic-gate 		return ("");
551*0Sstevel@tonic-gate 	return (dp);
552*0Sstevel@tonic-gate }
553*0Sstevel@tonic-gate 
554*0Sstevel@tonic-gate char *
555*0Sstevel@tonic-gate hasvfsopt(vfs, opt)
556*0Sstevel@tonic-gate 	struct vfstab *vfs;
557*0Sstevel@tonic-gate 	char *opt;
558*0Sstevel@tonic-gate {
559*0Sstevel@tonic-gate 	char *f, *opts;
560*0Sstevel@tonic-gate 	static char *tmpopts;
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	if (vfs->vfs_mntopts == NULL)
563*0Sstevel@tonic-gate 		return (NULL);
564*0Sstevel@tonic-gate 	if (tmpopts == 0) {
565*0Sstevel@tonic-gate 		tmpopts = (char *)calloc(256, sizeof (char));
566*0Sstevel@tonic-gate 		if (tmpopts == 0)
567*0Sstevel@tonic-gate 			return (0);
568*0Sstevel@tonic-gate 	}
569*0Sstevel@tonic-gate 	strncpy(tmpopts, vfs->vfs_mntopts, (sizeof (tmpopts) - 1));
570*0Sstevel@tonic-gate 	opts = tmpopts;
571*0Sstevel@tonic-gate 	f = mntopt(&opts);
572*0Sstevel@tonic-gate 	for (; *f; f = mntopt(&opts)) {
573*0Sstevel@tonic-gate 		if (strncmp(opt, f, strlen(opt)) == 0)
574*0Sstevel@tonic-gate 			return (f - tmpopts + vfs->vfs_mntopts);
575*0Sstevel@tonic-gate 	}
576*0Sstevel@tonic-gate 	return (NULL);
577*0Sstevel@tonic-gate }
578*0Sstevel@tonic-gate 
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate void
581*0Sstevel@tonic-gate usage()
582*0Sstevel@tonic-gate {
583*0Sstevel@tonic-gate 	(void) fprintf(stderr,
584*0Sstevel@tonic-gate "ufs usage: fsck [-F ufs] [generic options] [-o p,b=#,c,w] [special ....]\n");
585*0Sstevel@tonic-gate 	exit(31+1);
586*0Sstevel@tonic-gate }
587