xref: /original-bsd/sbin/fsck/main.c (revision 1aa52444)
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.8 (Berkeley) 05/03/88";
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 	struct worklist {
39 		int	pid;		/* pid of child doing the check */
40 		struct	worklist *next;	/* next in list */
41 		char	name[MAXMNTLEN];/* name of file system */
42 	} *listhead = 0, *freelist = 0, *badlist = 0;
43 	register struct worklist *wp, *pwp;
44 
45 	sync();
46 	while (--argc > 0 && **++argv == '-') {
47 		switch (*++*argv) {
48 
49 		case 'p':
50 			preen++;
51 			break;
52 
53 		case 'b':
54 			if (argv[0][1] != '\0') {
55 				bflag = atoi(argv[0]+1);
56 			} else {
57 				bflag = atoi(*++argv);
58 				argc--;
59 			}
60 			printf("Alternate super block location: %d\n", bflag);
61 			break;
62 
63 		case 'c':
64 			cvtflag++;
65 			break;
66 
67 		case 'd':
68 			debug++;
69 			break;
70 
71 		case 'n':	/* default no answer flag */
72 		case 'N':
73 			nflag++;
74 			yflag = 0;
75 			break;
76 
77 		case 'y':	/* default yes answer flag */
78 		case 'Y':
79 			yflag++;
80 			nflag = 0;
81 			break;
82 
83 		default:
84 			errexit("%c option?\n", **argv);
85 		}
86 	}
87 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
88 		(void)signal(SIGINT, catch);
89 	if (preen)
90 		(void)signal(SIGQUIT, catchquit);
91 	if (argc) {
92 		while (argc-- > 0) {
93 			hotroot = 0;
94 			checkfilesys(*argv++);
95 		}
96 		exit(0);
97 	}
98 	sumstatus = 0;
99 	passno = 1;
100 	do {
101 		anygtr = 0;
102 		if (setfsent() == 0)
103 			errexit("Can't open checklist file: %s\n", FSTAB);
104 		while ((fsp = getfsent()) != 0) {
105 			if (strcmp(fsp->fs_type, FSTAB_RW) &&
106 			    strcmp(fsp->fs_type, FSTAB_RO) &&
107 			    strcmp(fsp->fs_type, FSTAB_RQ))
108 				continue;
109 			if (preen == 0 ||
110 			    passno == 1 && fsp->fs_passno == passno) {
111 				name = blockcheck(fsp->fs_spec);
112 				if (name != NULL)
113 					checkfilesys(name);
114 				else if (preen)
115 					exit(8);
116 			} else if (fsp->fs_passno > passno) {
117 				anygtr = 1;
118 			} else if (fsp->fs_passno == passno) {
119 				name = blockcheck(fsp->fs_spec);
120 				if (name == NULL) {
121 					pwarn("BAD DISK NAME %s\n",
122 						fsp->fs_spec);
123 					sumstatus |= 8;
124 					continue;
125 				}
126 				pid = fork();
127 				if (pid < 0) {
128 					perror("fork");
129 					exit(8);
130 				}
131 				if (pid == 0) {
132 					(void)signal(SIGQUIT, voidquit);
133 					checkfilesys(name);
134 					exit(0);
135 				} else {
136 					if (freelist == 0) {
137 						wp = (struct worklist *) malloc
138 						    (sizeof(struct worklist));
139 					} else {
140 						wp = freelist;
141 						freelist = wp->next;
142 					}
143 					wp->next = listhead;
144 					listhead = wp;
145 					wp->pid = pid;
146 					sprintf(wp->name, "%s (%s)", name,
147 					    fsp->fs_file);
148 				}
149 			}
150 		}
151 		if (preen) {
152 			union wait status;
153 			while ((pid = wait(&status)) != -1) {
154 				sumstatus |= status.w_retcode;
155 				pwp = 0;
156 				for (wp = listhead; wp; pwp = wp, wp = wp->next)
157 					if (wp->pid == pid)
158 						break;
159 				if (wp == 0) {
160 					printf("Unknown pid %d\n", pid);
161 					continue;
162 				}
163 				if (pwp == 0)
164 					listhead = wp->next;
165 				else
166 					pwp->next = wp->next;
167 				if (status.w_retcode != 0) {
168 					wp->next = badlist;
169 					badlist = wp;
170 				} else {
171 					wp->next = freelist;
172 					freelist = wp;
173 				}
174 			}
175 		}
176 		passno++;
177 	} while (anygtr);
178 	if (sumstatus) {
179 		if (badlist == 0)
180 			exit(8);
181 		printf("THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
182 			badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
183 		for (wp = badlist; wp; wp = wp->next)
184 			printf("%s%s", wp->name, wp->next ? ", " : "\n");
185 		exit(8);
186 	}
187 	(void)endfsent();
188 	if (returntosingle)
189 		exit(2);
190 	exit(0);
191 }
192 
193 checkfilesys(filesys)
194 	char *filesys;
195 {
196 	daddr_t n_ffree, n_bfree;
197 	struct dups *dp;
198 	struct zlncnt *zlnp;
199 
200 	devname = filesys;
201 	if (setup(filesys) == 0) {
202 		if (preen)
203 			pfatal("CAN'T CHECK FILE SYSTEM.");
204 		return;
205 	}
206 	/*
207 	 * 1: scan inodes tallying blocks used
208 	 */
209 	if (preen == 0) {
210 		printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
211 		if (hotroot)
212 			printf("** Root file system\n");
213 		printf("** Phase 1 - Check Blocks and Sizes\n");
214 	}
215 	pass1();
216 
217 	/*
218 	 * 1b: locate first references to duplicates, if any
219 	 */
220 	if (duplist) {
221 		if (preen)
222 			pfatal("INTERNAL ERROR: dups with -p");
223 		printf("** Phase 1b - Rescan For More DUPS\n");
224 		pass1b();
225 	}
226 
227 	/*
228 	 * 2: traverse directories from root to mark all connected directories
229 	 */
230 	if (preen == 0)
231 		printf("** Phase 2 - Check Pathnames\n");
232 	pass2();
233 
234 	/*
235 	 * 3: scan inodes looking for disconnected directories
236 	 */
237 	if (preen == 0)
238 		printf("** Phase 3 - Check Connectivity\n");
239 	pass3();
240 
241 	/*
242 	 * 4: scan inodes looking for disconnected files; check reference counts
243 	 */
244 	if (preen == 0)
245 		printf("** Phase 4 - Check Reference Counts\n");
246 	pass4();
247 
248 	/*
249 	 * 5: check and repair resource counts in cylinder groups
250 	 */
251 	if (preen == 0)
252 		printf("** Phase 5 - Check Cyl groups\n");
253 	pass5();
254 
255 	/*
256 	 * print out summary statistics
257 	 */
258 	n_ffree = sblock.fs_cstotal.cs_nffree;
259 	n_bfree = sblock.fs_cstotal.cs_nbfree;
260 	pwarn("%d files, %d used, %d free ",
261 	    n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
262 	printf("(%d frags, %d blocks, %.1f%% fragmentation)\n",
263 	    n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize);
264 	if (debug && (n_files -= imax - ROOTINO - sblock.fs_cstotal.cs_nifree))
265 		printf("%d files missing\n", n_files);
266 	if (debug) {
267 		n_blks += sblock.fs_ncg *
268 			(cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
269 		n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
270 		n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
271 		if (n_blks -= fmax - (n_ffree + sblock.fs_frag * n_bfree))
272 			printf("%d blocks missing\n", n_blks);
273 		if (duplist != NULL) {
274 			printf("The following duplicate blocks remain:");
275 			for (dp = duplist; dp; dp = dp->next)
276 				printf(" %d,", dp->dup);
277 			printf("\n");
278 		}
279 		if (zlnhead != NULL) {
280 			printf("The following zero link count inodes remain:");
281 			for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
282 				printf(" %d,", zlnp->zlncnt);
283 			printf("\n");
284 		}
285 	}
286 	zlnhead = (struct zlncnt *)0;
287 	duplist = (struct dups *)0;
288 	if (dfile.mod) {
289 		(void)time(&sblock.fs_time);
290 		sbdirty();
291 	}
292 	ckfini();
293 	free(blockmap);
294 	free(statemap);
295 	free((char *)lncntp);
296 	if (!dfile.mod)
297 		return;
298 	if (!preen) {
299 		printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
300 		if (hotroot)
301 			printf("\n***** REBOOT UNIX *****\n");
302 	}
303 	if (hotroot) {
304 		sync();
305 		exit(4);
306 	}
307 }
308 
309 char *
310 blockcheck(name)
311 	char *name;
312 {
313 	struct stat stslash, stblock, stchar;
314 	char *raw;
315 	int looped = 0;
316 
317 	hotroot = 0;
318 	if (stat("/", &stslash) < 0){
319 		perror("/");
320 		printf("Can't stat root\n");
321 		return (0);
322 	}
323 retry:
324 	if (stat(name, &stblock) < 0){
325 		perror(name);
326 		printf("Can't stat %s\n", name);
327 		return (0);
328 	}
329 	if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
330 		if (stslash.st_dev == stblock.st_rdev) {
331 			hotroot++;
332 			return (name);
333 		}
334 		raw = rawname(name);
335 		if (stat(raw, &stchar) < 0){
336 			perror(raw);
337 			printf("Can't stat %s\n", raw);
338 			return (name);
339 		}
340 		if ((stchar.st_mode & S_IFMT) == S_IFCHR)
341 			return (raw);
342 		else {
343 			printf("%s is not a character device\n", raw);
344 			return (name);
345 		}
346 	} else if ((stblock.st_mode & S_IFMT) == S_IFCHR) {
347 		if (looped) {
348 			printf("Can't make sense out of name %s\n", name);
349 			return (0);
350 		}
351 		name = unrawname(name);
352 		looped++;
353 		goto retry;
354 	}
355 	printf("Can't make sense out of name %s\n", name);
356 	return (0);
357 }
358 
359 char *
360 unrawname(cp)
361 	char *cp;
362 {
363 	char *dp = rindex(cp, '/');
364 	struct stat stb;
365 
366 	if (dp == 0)
367 		return (cp);
368 	if (stat(cp, &stb) < 0)
369 		return (cp);
370 	if ((stb.st_mode&S_IFMT) != S_IFCHR)
371 		return (cp);
372 	if (*(dp+1) != 'r')
373 		return (cp);
374 	(void)strcpy(dp+1, dp+2);
375 	return (cp);
376 }
377 
378 char *
379 rawname(cp)
380 	char *cp;
381 {
382 	static char rawbuf[32];
383 	char *dp = rindex(cp, '/');
384 
385 	if (dp == 0)
386 		return (0);
387 	*dp = 0;
388 	(void)strcpy(rawbuf, cp);
389 	*dp = '/';
390 	(void)strcat(rawbuf, "/r");
391 	(void)strcat(rawbuf, dp+1);
392 	return (rawbuf);
393 }
394