main.c revision 8871
1219019Sgabor/*
2219019Sgabor * Copyright (c) 1980, 1986, 1993
3219019Sgabor *	The Regents of the University of California.  All rights reserved.
4219019Sgabor *
5219019Sgabor * Redistribution and use in source and binary forms, with or without
6219019Sgabor * modification, are permitted provided that the following conditions
7219019Sgabor * are met:
8219019Sgabor * 1. Redistributions of source code must retain the above copyright
9219019Sgabor *    notice, this list of conditions and the following disclaimer.
10219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright
11219019Sgabor *    notice, this list of conditions and the following disclaimer in the
12219019Sgabor *    documentation and/or other materials provided with the distribution.
13219019Sgabor * 3. All advertising materials mentioning features or use of this software
14219019Sgabor *    must display the following acknowledgement:
15219019Sgabor *	This product includes software developed by the University of
16219019Sgabor *	California, Berkeley and its contributors.
17219019Sgabor * 4. Neither the name of the University nor the names of its contributors
18219019Sgabor *    may be used to endorse or promote products derived from this software
19219019Sgabor *    without specific prior written permission.
20219019Sgabor *
21219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24219019Sgabor * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31219019Sgabor * SUCH DAMAGE.
32219019Sgabor */
33219019Sgabor
34219019Sgabor#ifndef lint
35219019Sgaborstatic const char copyright[] =
36219019Sgabor"@(#) Copyright (c) 1980, 1986, 1993\n\
37219019Sgabor	The Regents of the University of California.  All rights reserved.\n";
38219019Sgabor#endif /* not lint */
39219019Sgabor
40219019Sgabor#ifndef lint
41219019Sgaborstatic const char sccsid[] = "@(#)main.c	8.2 (Berkeley) 1/23/94";
42219019Sgabor#endif /* not lint */
43219019Sgabor
44219019Sgabor#include <sys/param.h>
45219019Sgabor#include <sys/time.h>
46219019Sgabor#include <sys/proc.h>
47219019Sgabor#include <sys/mount.h>
48219019Sgabor#include <ufs/ufs/dinode.h>
49219019Sgabor#include <ufs/ffs/fs.h>
50219019Sgabor#include <fstab.h>
51219019Sgabor#include <stdlib.h>
52219019Sgabor#include <unistd.h>
53219019Sgabor#include <string.h>
54219019Sgabor#include <ctype.h>
55219019Sgabor#include <stdio.h>
56219019Sgabor#include "fsck.h"
57219019Sgaborstatic int	argtoi __P((int flag, char *req, char *str, int base));
58219019Sgaborstatic int	docheck __P((struct fstab *fsp));
59219019Sgaborstatic int	checkfilesys __P((char *filesys, char *mntpt, long auxdata,
60219019Sgabor				  int child));
61219019Sgabor
62219019Sgaborint
63219019Sgabormain(argc, argv)
64219019Sgabor	int	argc;
65219019Sgabor	char	*argv[];
66219019Sgabor{
67219019Sgabor	int ch;
68219019Sgabor	int ret, maxrun = 0;
69219019Sgabor	extern char *optarg;
70219019Sgabor	extern int optind;
71219019Sgabor
72219019Sgabor	sync();
73219019Sgabor	while ((ch = getopt(argc, argv, "dfpnNyYb:c:l:m:")) != EOF) {
74219019Sgabor		switch (ch) {
75219019Sgabor		case 'p':
76219019Sgabor			preen++;
77219019Sgabor			break;
78219019Sgabor
79219019Sgabor		case 'b':
80219019Sgabor			bflag = argtoi('b', "number", optarg, 10);
81219019Sgabor			printf("Alternate super block location: %d\n", bflag);
82219019Sgabor			break;
83260264Sdim
84219019Sgabor		case 'c':
85219019Sgabor			cvtlevel = argtoi('c', "conversion level", optarg, 10);
86219019Sgabor			break;
87219019Sgabor
88219019Sgabor		case 'd':
89219019Sgabor			debug++;
90219019Sgabor			break;
91219019Sgabor
92219019Sgabor		case 'f':
93219019Sgabor			fflag++;
94219019Sgabor			break;
95219019Sgabor
96219019Sgabor		case 'l':
97219019Sgabor			maxrun = argtoi('l', "number", optarg, 10);
98219019Sgabor			break;
99219019Sgabor
100219019Sgabor		case 'm':
101260264Sdim			lfmode = argtoi('m', "mode", optarg, 8);
102219019Sgabor			if (lfmode &~ 07777)
103219019Sgabor				errexit("bad mode to -m: %o\n", lfmode);
104219019Sgabor			printf("** lost+found creation mode %o\n", lfmode);
105219019Sgabor			break;
106219019Sgabor
107219019Sgabor		case 'n':
108219019Sgabor		case 'N':
109219019Sgabor			nflag++;
110219019Sgabor			yflag = 0;
111219019Sgabor			break;
112219019Sgabor
113219019Sgabor		case 'y':
114219019Sgabor		case 'Y':
115219019Sgabor			yflag++;
116219019Sgabor			nflag = 0;
117219019Sgabor			break;
118219019Sgabor
119219019Sgabor		default:
120219019Sgabor			errexit("%c option?\n", ch);
121219019Sgabor		}
122219019Sgabor	}
123219019Sgabor	argc -= optind;
124219019Sgabor	argv += optind;
125219019Sgabor	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
126219019Sgabor		(void)signal(SIGINT, catch);
127219019Sgabor	if (preen)
128219019Sgabor		(void)signal(SIGQUIT, catchquit);
129219019Sgabor	if (argc) {
130219019Sgabor		while (argc-- > 0)
131219019Sgabor			(void)checkfilesys(blockcheck(*argv++), 0, 0L, 0);
132219019Sgabor		exit(0);
133219019Sgabor	}
134219019Sgabor	ret = checkfstab(preen, maxrun, docheck, checkfilesys);
135219019Sgabor	if (returntosingle)
136219019Sgabor		exit(2);
137219019Sgabor	exit(ret);
138219019Sgabor}
139219019Sgabor
140219019Sgaborint
141219019Sgaborargtoi(flag, req, str, base)
142219019Sgabor	int flag;
143219019Sgabor	char *req, *str;
144219019Sgabor	int base;
145219019Sgabor{
146219019Sgabor	char *cp;
147219019Sgabor	int ret;
148219019Sgabor
149219019Sgabor	ret = (int)strtol(str, &cp, base);
150219019Sgabor	if (cp == str || *cp)
151219019Sgabor		errexit("-%c flag requires a %s\n", flag, req);
152282275Stijl	return (ret);
153219019Sgabor}
154219019Sgabor
155282275Stijl/*
156219019Sgabor * Determine whether a filesystem should be checked.
157219019Sgabor */
158219019Sgaborint
159219019Sgabordocheck(fsp)
160219019Sgabor	register struct fstab *fsp;
161219019Sgabor{
162219019Sgabor
163219019Sgabor	if (strcmp(fsp->fs_vfstype, "ufs") ||
164219019Sgabor	    (strcmp(fsp->fs_type, FSTAB_RW) &&
165219019Sgabor	     strcmp(fsp->fs_type, FSTAB_RO)) ||
166219019Sgabor	    fsp->fs_passno == 0)
167219019Sgabor		return (0);
168219019Sgabor	return (1);
169219019Sgabor}
170219019Sgabor
171219019Sgabor/*
172219019Sgabor * Check the specified filesystem.
173219019Sgabor */
174219019Sgabor/* ARGSUSED */
175219019Sgaborint
176219019Sgaborcheckfilesys(filesys, mntpt, auxdata, child)
177219019Sgabor	char *filesys, *mntpt;
178219019Sgabor	long auxdata;
179219019Sgabor	int child;
180219019Sgabor{
181219019Sgabor	daddr_t n_ffree, n_bfree;
182219019Sgabor	struct dups *dp;
183219019Sgabor	struct zlncnt *zlnp;
184219019Sgabor	int cylno;
185219019Sgabor
186219019Sgabor	if (preen && child)
187219019Sgabor		(void)signal(SIGQUIT, voidquit);
188219019Sgabor	cdevname = filesys;
189219019Sgabor	if (debug && preen)
190219019Sgabor		pwarn("starting\n");
191219019Sgabor	if (setup(filesys) == 0) {
192219019Sgabor		if (preen)
193219019Sgabor			pfatal("CAN'T CHECK FILE SYSTEM.");
194219019Sgabor		return (0);
195219019Sgabor	}
196219019Sgabor
197219019Sgabor	if (preen && sblock.fs_clean && !fflag) {
198219019Sgabor		pwarn("clean, %ld free ", sblock.fs_cstotal.cs_nffree +
199219019Sgabor			sblock.fs_frag * sblock.fs_cstotal.cs_nbfree);
200219019Sgabor		printf("(%ld frags, %ld blocks, %.1f%% fragmentation)\n",
201219019Sgabor			sblock.fs_cstotal.cs_nffree,
202219019Sgabor			sblock.fs_cstotal.cs_nbfree,
203219019Sgabor			(float)(sblock.fs_cstotal.cs_nffree * 100) /
204219019Sgabor			sblock.fs_dsize);
205219019Sgabor		return(0);
206219019Sgabor	}
207219019Sgabor
208219019Sgabor	/*
209219019Sgabor	 * 1: scan inodes tallying blocks used
210219019Sgabor	 */
211219019Sgabor	if (preen == 0) {
212219019Sgabor		printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
213219019Sgabor		if (hotroot)
214219019Sgabor			printf("** Root file system\n");
215219019Sgabor		printf("** Phase 1 - Check Blocks and Sizes\n");
216219019Sgabor	}
217219019Sgabor	pass1();
218219019Sgabor
219219019Sgabor	/*
220219019Sgabor	 * 1b: locate first references to duplicates, if any
221219019Sgabor	 */
222219019Sgabor	if (duplist) {
223219019Sgabor		if (preen)
224219019Sgabor			pfatal("INTERNAL ERROR: dups with -p");
225219019Sgabor		printf("** Phase 1b - Rescan For More DUPS\n");
226219019Sgabor		pass1b();
227219019Sgabor	}
228219019Sgabor
229219019Sgabor	/*
230219019Sgabor	 * 2: traverse directories from root to mark all connected directories
231219019Sgabor	 */
232219019Sgabor	if (preen == 0)
233219019Sgabor		printf("** Phase 2 - Check Pathnames\n");
234219019Sgabor	pass2();
235219019Sgabor
236219019Sgabor	/*
237219019Sgabor	 * 3: scan inodes looking for disconnected directories
238219019Sgabor	 */
239219019Sgabor	if (preen == 0)
240219019Sgabor		printf("** Phase 3 - Check Connectivity\n");
241219019Sgabor	pass3();
242219019Sgabor
243219019Sgabor	/*
244219019Sgabor	 * 4: scan inodes looking for disconnected files; check reference counts
245219019Sgabor	 */
246219019Sgabor	if (preen == 0)
247219019Sgabor		printf("** Phase 4 - Check Reference Counts\n");
248219019Sgabor	pass4();
249219019Sgabor
250219019Sgabor	/*
251219019Sgabor	 * 5: check and repair resource counts in cylinder groups
252219019Sgabor	 */
253219019Sgabor	if (preen == 0)
254219019Sgabor		printf("** Phase 5 - Check Cyl groups\n");
255219019Sgabor	pass5();
256219019Sgabor
257219019Sgabor	/*
258219019Sgabor	 * print out summary statistics
259219019Sgabor	 */
260219019Sgabor	n_ffree = sblock.fs_cstotal.cs_nffree;
261219019Sgabor	n_bfree = sblock.fs_cstotal.cs_nbfree;
262219019Sgabor	pwarn("%ld files, %ld used, %ld free ",
263219019Sgabor	    n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
264219019Sgabor	printf("(%ld frags, %ld blocks, %ld.%ld%% fragmentation)\n",
265219019Sgabor	    n_ffree, n_bfree, (n_ffree * 100) / sblock.fs_dsize,
266219019Sgabor	    ((n_ffree * 1000 + sblock.fs_dsize / 2) / sblock.fs_dsize) % 10);
267219019Sgabor	if (debug &&
268219019Sgabor	    (n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree))
269219019Sgabor		printf("%ld files missing\n", n_files);
270219019Sgabor	if (debug) {
271219019Sgabor		n_blks += sblock.fs_ncg *
272219019Sgabor			(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
273219019Sgabor		n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
274219019Sgabor		n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
275219019Sgabor		if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
276219019Sgabor			printf("%ld blocks missing\n", n_blks);
277219019Sgabor		if (duplist != NULL) {
278219019Sgabor			printf("The following duplicate blocks remain:");
279219019Sgabor			for (dp = duplist; dp; dp = dp->next)
280219019Sgabor				printf(" %ld,", dp->dup);
281219019Sgabor			printf("\n");
282219019Sgabor		}
283219019Sgabor		if (zlnhead != NULL) {
284219019Sgabor			printf("The following zero link count inodes remain:");
285219019Sgabor			for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
286219019Sgabor				printf(" %lu,", zlnp->zlncnt);
287219019Sgabor			printf("\n");
288219019Sgabor		}
289219019Sgabor	}
290219019Sgabor	zlnhead = (struct zlncnt *)0;
291219019Sgabor	duplist = (struct dups *)0;
292219019Sgabor	muldup = (struct dups *)0;
293219019Sgabor	inocleanup();
294219019Sgabor	if (fsmodified) {
295219019Sgabor		(void)time(&sblock.fs_time);
296219019Sgabor		sbdirty();
297219019Sgabor	}
298219019Sgabor	if (cvtlevel && sblk.b_dirty) {
299219019Sgabor		/*
300219019Sgabor		 * Write out the duplicate super blocks
301219019Sgabor		 */
302219019Sgabor		for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
303219019Sgabor			bwrite(fswritefd, (char *)&sblock,
304219019Sgabor			    fsbtodb(&sblock, cgsblock(&sblock, cylno)), SBSIZE);
305219019Sgabor	}
306219019Sgabor	ckfini();
307219019Sgabor	free(blockmap);
308219019Sgabor	free(statemap);
309219019Sgabor	free((char *)lncntp);
310219019Sgabor	if (!fsmodified)
311219019Sgabor		return (0);
312219019Sgabor	if (!preen)
313219019Sgabor		printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
314219019Sgabor	if (hotroot) {
315219019Sgabor		struct statfs stfs_buf;
316219019Sgabor		/*
317219019Sgabor		 * We modified the root.  Do a mount update on
318219019Sgabor		 * it, unless it is read-write, so we can continue.
319219019Sgabor		 */
320219019Sgabor		if (statfs("/", &stfs_buf) == 0) {
321219019Sgabor			long flags = stfs_buf.f_flags;
322219019Sgabor			struct ufs_args args;
323219019Sgabor			int ret;
324219019Sgabor
325219019Sgabor			if (flags & MNT_RDONLY) {
326219019Sgabor				args.fspec = 0;
327219019Sgabor				args.export.ex_flags = 0;
328219019Sgabor				args.export.ex_root = 0;
329219019Sgabor				flags |= MNT_UPDATE | MNT_RELOAD;
330219019Sgabor				ret = mount(MOUNT_UFS, "/", flags, &args);
331219019Sgabor				if (ret == 0)
332219019Sgabor					return(0);
333219019Sgabor			}
334219019Sgabor		}
335219019Sgabor		if (!preen)
336219019Sgabor			printf("\n***** REBOOT NOW *****\n");
337219019Sgabor		sync();
338219019Sgabor		return (4);
339219019Sgabor	}
340219019Sgabor	return (0);
341219019Sgabor}
342219019Sgabor