xref: /original-bsd/sbin/fsck/main.c (revision 61b6c03f)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)main.c	5.4 (Berkeley) 03/05/86";
15 #endif not lint
16 
17 #include <sys/param.h>
18 #include <sys/inode.h>
19 #include <sys/fs.h>
20 #include <sys/stat.h>
21 #include <sys/wait.h>
22 #include <fstab.h>
23 #include <strings.h>
24 #include "fsck.h"
25 
26 char	*rawname(), *unrawname(), *blockcheck();
27 int	catch(), catchquit(), voidquit();
28 int	returntosingle;
29 int	(*signal())();
30 
31 main(argc, argv)
32 	int	argc;
33 	char	*argv[];
34 {
35 	struct fstab *fsp;
36 	int pid, passno, anygtr, sumstatus;
37 	char *name;
38 
39 	sync();
40 	while (--argc > 0 && **++argv == '-') {
41 		switch (*++*argv) {
42 
43 		case 'p':
44 			preen++;
45 			break;
46 
47 		case 'b':
48 			if (argv[0][1] != '\0') {
49 				bflag = atoi(argv[0]+1);
50 			} else {
51 				bflag = atoi(*++argv);
52 				argc--;
53 			}
54 			printf("Alternate super block location: %d\n", bflag);
55 			break;
56 
57 		case 'd':
58 			debug++;
59 			break;
60 
61 		case 'n':	/* default no answer flag */
62 		case 'N':
63 			nflag++;
64 			yflag = 0;
65 			break;
66 
67 		case 'y':	/* default yes answer flag */
68 		case 'Y':
69 			yflag++;
70 			nflag = 0;
71 			break;
72 
73 		default:
74 			errexit("%c option?\n", **argv);
75 		}
76 	}
77 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
78 		(void)signal(SIGINT, catch);
79 	if (preen)
80 		(void)signal(SIGQUIT, catchquit);
81 	if (argc) {
82 		while (argc-- > 0) {
83 			hotroot = 0;
84 			checkfilesys(*argv++);
85 		}
86 		exit(0);
87 	}
88 	sumstatus = 0;
89 	passno = 1;
90 	do {
91 		anygtr = 0;
92 		if (setfsent() == 0)
93 			errexit("Can't open checklist file: %s\n", FSTAB);
94 		while ((fsp = getfsent()) != 0) {
95 			if (strcmp(fsp->fs_type, FSTAB_RW) &&
96 			    strcmp(fsp->fs_type, FSTAB_RO) &&
97 			    strcmp(fsp->fs_type, FSTAB_RQ))
98 				continue;
99 			if (preen == 0 ||
100 			    passno == 1 && fsp->fs_passno == passno) {
101 				name = blockcheck(fsp->fs_spec);
102 				if (name != NULL)
103 					checkfilesys(name);
104 				else if (preen)
105 					exit(8);
106 			} else if (fsp->fs_passno > passno) {
107 				anygtr = 1;
108 			} else if (fsp->fs_passno == passno) {
109 				pid = fork();
110 				if (pid < 0) {
111 					perror("fork");
112 					exit(8);
113 				}
114 				if (pid == 0) {
115 					(void)signal(SIGQUIT, voidquit);
116 					name = blockcheck(fsp->fs_spec);
117 					if (name == NULL)
118 						exit(8);
119 					checkfilesys(name);
120 					exit(0);
121 				}
122 			}
123 		}
124 		if (preen) {
125 			union wait status;
126 			while (wait(&status) != -1)
127 				sumstatus |= status.w_retcode;
128 		}
129 		passno++;
130 	} while (anygtr);
131 	if (sumstatus)
132 		exit(8);
133 	(void)endfsent();
134 	if (returntosingle)
135 		exit(2);
136 	exit(0);
137 }
138 
139 checkfilesys(filesys)
140 	char *filesys;
141 {
142 	daddr_t n_ffree, n_bfree;
143 	struct dups *dp;
144 	struct zlncnt *zlnp;
145 
146 	devname = filesys;
147 	if (setup(filesys) == 0) {
148 		if (preen)
149 			pfatal("CAN'T CHECK FILE SYSTEM.");
150 		return;
151 	}
152 	/*
153 	 * 1: scan inodes tallying blocks used
154 	 */
155 	if (preen == 0) {
156 		printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
157 		if (hotroot)
158 			printf("** Root file system\n");
159 		printf("** Phase 1 - Check Blocks and Sizes\n");
160 	}
161 	pass1();
162 
163 	/*
164 	 * 1b: locate first references to duplicates, if any
165 	 */
166 	if (duplist) {
167 		if (preen)
168 			pfatal("INTERNAL ERROR: dups with -p");
169 		printf("** Phase 1b - Rescan For More DUPS\n");
170 		pass1b();
171 	}
172 
173 	/*
174 	 * 2: traverse directories from root to mark all connected directories
175 	 */
176 	if (preen == 0)
177 		printf("** Phase 2 - Check Pathnames\n");
178 	pass2();
179 
180 	/*
181 	 * 3: scan inodes looking for disconnected directories
182 	 */
183 	if (preen == 0)
184 		printf("** Phase 3 - Check Connectivity\n");
185 	pass3();
186 
187 	/*
188 	 * 4: scan inodes looking for disconnected files; check reference counts
189 	 */
190 	if (preen == 0)
191 		printf("** Phase 4 - Check Reference Counts\n");
192 	pass4();
193 
194 	/*
195 	 * 5: check and repair resource counts in cylinder groups
196 	 */
197 	if (preen == 0)
198 		printf("** Phase 5 - Check Cyl groups\n");
199 	pass5();
200 
201 	/*
202 	 * print out summary statistics
203 	 */
204 	n_ffree = sblock.fs_cstotal.cs_nffree;
205 	n_bfree = sblock.fs_cstotal.cs_nbfree;
206 	pwarn("%d files, %d used, %d free ",
207 	    n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
208 	printf("(%d frags, %d blocks, %.1f%% fragmentation)\n",
209 	    n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize);
210 	if (debug && (n_files -= imax - ROOTINO - sblock.fs_cstotal.cs_nifree))
211 		printf("%d files missing\n", n_files);
212 	if (debug) {
213 		n_blks += sblock.fs_ncg *
214 			(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
215 		n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
216 		n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
217 		if (n_blks -= fmax - (n_ffree + sblock.fs_frag * n_bfree))
218 			printf("%d blocks missing\n", n_blks);
219 		if (duplist != NULL) {
220 			printf("The following duplicate blocks remain:");
221 			for (dp = duplist; dp; dp = dp->next)
222 				printf(" %d,", dp->dup);
223 			printf("\n");
224 		}
225 		if (zlnhead != NULL) {
226 			printf("The following zero link count inodes remain:");
227 			for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
228 				printf(" %d,", zlnp->zlncnt);
229 			printf("\n");
230 		}
231 	}
232 	zlnhead = (struct zlncnt *)0;
233 	duplist = (struct dups *)0;
234 	if (dfile.mod) {
235 		(void)time(&sblock.fs_time);
236 		sbdirty();
237 	}
238 	ckfini();
239 	free(blockmap);
240 	free(statemap);
241 	free((char *)lncntp);
242 	if (!dfile.mod)
243 		return;
244 	if (!preen) {
245 		printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
246 		if (hotroot)
247 			printf("\n***** REBOOT UNIX *****\n");
248 	}
249 	if (hotroot) {
250 		sync();
251 		exit(4);
252 	}
253 }
254 
255 char *
256 blockcheck(name)
257 	char *name;
258 {
259 	struct stat stslash, stblock, stchar;
260 	char *raw;
261 	int looped = 0;
262 
263 	hotroot = 0;
264 	if (stat("/", &stslash) < 0){
265 		printf("Can't stat root\n");
266 		return (0);
267 	}
268 retry:
269 	if (stat(name, &stblock) < 0){
270 		printf("Can't stat %s\n", name);
271 		return (0);
272 	}
273 	if (stblock.st_mode & S_IFBLK) {
274 		raw = rawname(name);
275 		if (stat(raw, &stchar) < 0){
276 			printf("Can't stat %s\n", raw);
277 			return (0);
278 		}
279 		if (stchar.st_mode & S_IFCHR) {
280 			if (stslash.st_dev == stblock.st_rdev) {
281 				hotroot++;
282 				raw = unrawname(name);
283 			}
284 			return (raw);
285 		} else {
286 			printf("%s is not a character device\n", raw);
287 			return (0);
288 		}
289 	} else if (stblock.st_mode & S_IFCHR) {
290 		if (looped) {
291 			printf("Can't make sense out of name %s\n", name);
292 			return (0);
293 		}
294 		name = unrawname(name);
295 		looped++;
296 		goto retry;
297 	}
298 	printf("Can't make sense out of name %s\n", name);
299 	return (0);
300 }
301 
302 char *
303 unrawname(cp)
304 	char *cp;
305 {
306 	char *dp = rindex(cp, '/');
307 	struct stat stb;
308 
309 	if (dp == 0)
310 		return (cp);
311 	if (stat(cp, &stb) < 0)
312 		return (cp);
313 	if ((stb.st_mode&S_IFMT) != S_IFCHR)
314 		return (cp);
315 	if (*(dp+1) != 'r')
316 		return (cp);
317 	(void)strcpy(dp+1, dp+2);
318 	return (cp);
319 }
320 
321 char *
322 rawname(cp)
323 	char *cp;
324 {
325 	static char rawbuf[32];
326 	char *dp = rindex(cp, '/');
327 
328 	if (dp == 0)
329 		return (0);
330 	*dp = 0;
331 	(void)strcpy(rawbuf, cp);
332 	*dp = '/';
333 	(void)strcat(rawbuf, "/r");
334 	(void)strcat(rawbuf, dp+1);
335 	return (rawbuf);
336 }
337