xref: /original-bsd/sbin/fsck/main.c (revision a0411884)
1 /*
2  * Copyright (c) 1980, 1986, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1986, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)main.c	8.2 (Berkeley) 01/23/94";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/time.h>
20 #include <sys/mount.h>
21 #include <ufs/ufs/dinode.h>
22 #include <ufs/ffs/fs.h>
23 #include <fstab.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <stdio.h>
28 #include "fsck.h"
29 
30 void	catch(), catchquit(), voidquit();
31 int	returntosingle;
32 
33 main(argc, argv)
34 	int	argc;
35 	char	*argv[];
36 {
37 	int ch;
38 	int ret, maxrun = 0;
39 	extern int docheck(), checkfilesys();
40 	extern char *optarg, *blockcheck();
41 	extern int optind;
42 
43 	sync();
44 	while ((ch = getopt(argc, argv, "dpnNyYb:c:l:m:")) != EOF) {
45 		switch (ch) {
46 		case 'p':
47 			preen++;
48 			break;
49 
50 		case 'b':
51 			bflag = argtoi('b', "number", optarg, 10);
52 			printf("Alternate super block location: %d\n", bflag);
53 			break;
54 
55 		case 'c':
56 			cvtlevel = argtoi('c', "conversion level", optarg, 10);
57 			break;
58 
59 		case 'd':
60 			debug++;
61 			break;
62 
63 		case 'l':
64 			maxrun = argtoi('l', "number", optarg, 10);
65 			break;
66 
67 		case 'm':
68 			lfmode = argtoi('m', "mode", optarg, 8);
69 			if (lfmode &~ 07777)
70 				errexit("bad mode to -m: %o\n", lfmode);
71 			printf("** lost+found creation mode %o\n", lfmode);
72 			break;
73 
74 		case 'n':
75 		case 'N':
76 			nflag++;
77 			yflag = 0;
78 			break;
79 
80 		case 'y':
81 		case 'Y':
82 			yflag++;
83 			nflag = 0;
84 			break;
85 
86 		default:
87 			errexit("%c option?\n", ch);
88 		}
89 	}
90 	argc -= optind;
91 	argv += optind;
92 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
93 		(void)signal(SIGINT, catch);
94 	if (preen)
95 		(void)signal(SIGQUIT, catchquit);
96 	if (argc) {
97 		while (argc-- > 0)
98 			(void)checkfilesys(blockcheck(*argv++), 0, 0L, 0);
99 		exit(0);
100 	}
101 	ret = checkfstab(preen, maxrun, docheck, checkfilesys);
102 	if (returntosingle)
103 		exit(2);
104 	exit(ret);
105 }
106 
107 argtoi(flag, req, str, base)
108 	int flag;
109 	char *req, *str;
110 	int base;
111 {
112 	char *cp;
113 	int ret;
114 
115 	ret = (int)strtol(str, &cp, base);
116 	if (cp == str || *cp)
117 		errexit("-%c flag requires a %s\n", flag, req);
118 	return (ret);
119 }
120 
121 /*
122  * Determine whether a filesystem should be checked.
123  */
124 docheck(fsp)
125 	register struct fstab *fsp;
126 {
127 
128 	if (strcmp(fsp->fs_vfstype, "ufs") ||
129 	    (strcmp(fsp->fs_type, FSTAB_RW) &&
130 	     strcmp(fsp->fs_type, FSTAB_RO)) ||
131 	    fsp->fs_passno == 0)
132 		return (0);
133 	return (1);
134 }
135 
136 /*
137  * Check the specified filesystem.
138  */
139 /* ARGSUSED */
140 checkfilesys(filesys, mntpt, auxdata, child)
141 	char *filesys, *mntpt;
142 	long auxdata;
143 {
144 	daddr_t n_ffree, n_bfree;
145 	struct dups *dp;
146 	struct zlncnt *zlnp;
147 	int cylno;
148 
149 	if (preen && child)
150 		(void)signal(SIGQUIT, voidquit);
151 	cdevname = filesys;
152 	if (debug && preen)
153 		pwarn("starting\n");
154 	if (setup(filesys) == 0) {
155 		if (preen)
156 			pfatal("CAN'T CHECK FILE SYSTEM.");
157 		return (0);
158 	}
159 	/*
160 	 * 1: scan inodes tallying blocks used
161 	 */
162 	if (preen == 0) {
163 		printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
164 		if (hotroot)
165 			printf("** Root file system\n");
166 		printf("** Phase 1 - Check Blocks and Sizes\n");
167 	}
168 	pass1();
169 
170 	/*
171 	 * 1b: locate first references to duplicates, if any
172 	 */
173 	if (duplist) {
174 		if (preen)
175 			pfatal("INTERNAL ERROR: dups with -p");
176 		printf("** Phase 1b - Rescan For More DUPS\n");
177 		pass1b();
178 	}
179 
180 	/*
181 	 * 2: traverse directories from root to mark all connected directories
182 	 */
183 	if (preen == 0)
184 		printf("** Phase 2 - Check Pathnames\n");
185 	pass2();
186 
187 	/*
188 	 * 3: scan inodes looking for disconnected directories
189 	 */
190 	if (preen == 0)
191 		printf("** Phase 3 - Check Connectivity\n");
192 	pass3();
193 
194 	/*
195 	 * 4: scan inodes looking for disconnected files; check reference counts
196 	 */
197 	if (preen == 0)
198 		printf("** Phase 4 - Check Reference Counts\n");
199 	pass4();
200 
201 	/*
202 	 * 5: check and repair resource counts in cylinder groups
203 	 */
204 	if (preen == 0)
205 		printf("** Phase 5 - Check Cyl groups\n");
206 	pass5();
207 
208 	/*
209 	 * print out summary statistics
210 	 */
211 	n_ffree = sblock.fs_cstotal.cs_nffree;
212 	n_bfree = sblock.fs_cstotal.cs_nbfree;
213 	pwarn("%ld files, %ld used, %ld free ",
214 	    n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
215 	printf("(%ld frags, %ld blocks, %d.%d%% fragmentation)\n",
216 	    n_ffree, n_bfree, (n_ffree * 100) / sblock.fs_dsize,
217 	    ((n_ffree * 1000 + sblock.fs_dsize / 2) / sblock.fs_dsize) % 10);
218 	if (debug &&
219 	    (n_files -= maxino - ROOTINO - sblock.fs_cstotal.cs_nifree))
220 		printf("%ld files missing\n", n_files);
221 	if (debug) {
222 		n_blks += sblock.fs_ncg *
223 			(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
224 		n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
225 		n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
226 		if (n_blks -= maxfsblock - (n_ffree + sblock.fs_frag * n_bfree))
227 			printf("%ld blocks missing\n", n_blks);
228 		if (duplist != NULL) {
229 			printf("The following duplicate blocks remain:");
230 			for (dp = duplist; dp; dp = dp->next)
231 				printf(" %ld,", dp->dup);
232 			printf("\n");
233 		}
234 		if (zlnhead != NULL) {
235 			printf("The following zero link count inodes remain:");
236 			for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
237 				printf(" %lu,", zlnp->zlncnt);
238 			printf("\n");
239 		}
240 	}
241 	zlnhead = (struct zlncnt *)0;
242 	duplist = (struct dups *)0;
243 	muldup = (struct dups *)0;
244 	inocleanup();
245 	if (fsmodified) {
246 		(void)time(&sblock.fs_time);
247 		sbdirty();
248 	}
249 	if (cvtlevel && sblk.b_dirty) {
250 		/*
251 		 * Write out the duplicate super blocks
252 		 */
253 		for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
254 			bwrite(fswritefd, (char *)&sblock,
255 			    fsbtodb(&sblock, cgsblock(&sblock, cylno)), SBSIZE);
256 	}
257 	ckfini();
258 	free(blockmap);
259 	free(statemap);
260 	free((char *)lncntp);
261 	if (!fsmodified)
262 		return (0);
263 	if (!preen)
264 		printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
265 	if (hotroot) {
266 		struct statfs stfs_buf;
267 		/*
268 		 * We modified the root.  Do a mount update on
269 		 * it, unless it is read-write, so we can continue.
270 		 */
271 		if (statfs("/", &stfs_buf) == 0) {
272 			long flags = stfs_buf.f_flags;
273 			struct ufs_args args;
274 			int ret;
275 
276 			if (flags & MNT_RDONLY) {
277 				args.fspec = 0;
278 				args.export.ex_flags = 0;
279 				args.export.ex_root = 0;
280 				flags |= MNT_UPDATE | MNT_RELOAD;
281 				ret = mount(MOUNT_UFS, "/", flags, &args);
282 				if (ret == 0)
283 					return(0);
284 			}
285 		}
286 		if (!preen)
287 			printf("\n***** REBOOT NOW *****\n");
288 		sync();
289 		return (4);
290 	}
291 	return (0);
292 }
293