BSD 4_3_Tahoe release
[unix-history] / usr / src / etc / fsck / main.c
CommitLineData
76797561
DF
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
8char copyright[] =
9"@(#) Copyright (c) 1980 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
fa95fc59 13#ifndef lint
ca67e7b4 14static char sccsid[] = "@(#)main.c 5.8 (Berkeley) 5/3/88";
76797561 15#endif not lint
07670f7d 16
4d308541 17#include <sys/param.h>
4d308541 18#include <sys/inode.h>
f7635e39 19#include <sys/fs.h>
7718c0e6
KM
20#include <sys/stat.h>
21#include <sys/wait.h>
22#include <fstab.h>
23#include <strings.h>
f7635e39 24#include "fsck.h"
6e884967 25
7718c0e6 26char *rawname(), *unrawname(), *blockcheck();
3cfe4689
MK
27int catch(), catchquit(), voidquit();
28int returntosingle;
7718c0e6
KM
29int (*signal())();
30
31main(argc, argv)
32 int argc;
33 char *argv[];
34{
35 struct fstab *fsp;
36 int pid, passno, anygtr, sumstatus;
37 char *name;
ca67e7b4
C
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;
7718c0e6
KM
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
d3e80ec3
KM
63 case 'c':
64 cvtflag++;
65 break;
66
7718c0e6
KM
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);
3cfe4689
MK
89 if (preen)
90 (void)signal(SIGQUIT, catchquit);
7718c0e6
KM
91 if (argc) {
92 while (argc-- > 0) {
93 hotroot = 0;
cfbff64d 94 checkfilesys(*argv++);
7718c0e6
KM
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) {
844eeb65
KM
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 }
7718c0e6
KM
126 pid = fork();
127 if (pid < 0) {
128 perror("fork");
129 exit(8);
130 }
131 if (pid == 0) {
3cfe4689 132 (void)signal(SIGQUIT, voidquit);
7718c0e6
KM
133 checkfilesys(name);
134 exit(0);
ca67e7b4
C
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);
7718c0e6
KM
148 }
149 }
150 }
151 if (preen) {
152 union wait status;
ca67e7b4 153 while ((pid = wait(&status)) != -1) {
7718c0e6 154 sumstatus |= status.w_retcode;
ca67e7b4
C
155 pwp = 0;
156 for (wp = listhead; wp; pwp = wp, wp = wp->next)
157 if (wp->pid == pid)
844eeb65 158 break;
ca67e7b4
C
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;
844eeb65
KM
173 }
174 }
7718c0e6
KM
175 }
176 passno++;
177 } while (anygtr);
844eeb65
KM
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:");
ca67e7b4
C
183 for (wp = badlist; wp; wp = wp->next)
184 printf("%s%s", wp->name, wp->next ? ", " : "\n");
7718c0e6 185 exit(8);
844eeb65 186 }
7718c0e6 187 (void)endfsent();
3cfe4689
MK
188 if (returntosingle)
189 exit(2);
7718c0e6
KM
190 exit(0);
191}
192
d2c95d76
BJ
193checkfilesys(filesys)
194 char *filesys;
6e884967 195{
993a756c 196 daddr_t n_ffree, n_bfree;
d4233021 197 struct dups *dp;
1a02fd3a 198 struct zlncnt *zlnp;
6e884967 199
d2c95d76
BJ
200 devname = filesys;
201 if (setup(filesys) == 0) {
6e884967 202 if (preen)
d2c95d76 203 pfatal("CAN'T CHECK FILE SYSTEM.");
6e884967
KM
204 return;
205 }
993a756c
KM
206 /*
207 * 1: scan inodes tallying blocks used
208 */
690f77ba
KM
209 if (preen == 0) {
210 printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
6e884967
KM
211 if (hotroot)
212 printf("** Root file system\n");
213 printf("** Phase 1 - Check Blocks and Sizes\n");
214 }
d2c95d76
BJ
215 pass1();
216
993a756c
KM
217 /*
218 * 1b: locate first references to duplicates, if any
219 */
62e6c152 220 if (duplist) {
d2c95d76
BJ
221 if (preen)
222 pfatal("INTERNAL ERROR: dups with -p");
223 printf("** Phase 1b - Rescan For More DUPS\n");
224 pass1b();
225 }
226
993a756c
KM
227 /*
228 * 2: traverse directories from root to mark all connected directories
229 */
d2c95d76
BJ
230 if (preen == 0)
231 printf("** Phase 2 - Check Pathnames\n");
232 pass2();
233
993a756c
KM
234 /*
235 * 3: scan inodes looking for disconnected directories
236 */
d2c95d76
BJ
237 if (preen == 0)
238 printf("** Phase 3 - Check Connectivity\n");
239 pass3();
240
993a756c
KM
241 /*
242 * 4: scan inodes looking for disconnected files; check reference counts
243 */
d2c95d76
BJ
244 if (preen == 0)
245 printf("** Phase 4 - Check Reference Counts\n");
246 pass4();
247
993a756c
KM
248 /*
249 * 5: check and repair resource counts in cylinder groups
250 */
d2c95d76
BJ
251 if (preen == 0)
252 printf("** Phase 5 - Check Cyl groups\n");
253 pass5();
254
993a756c
KM
255 /*
256 * print out summary statistics
257 */
258 n_ffree = sblock.fs_cstotal.cs_nffree;
259 n_bfree = sblock.fs_cstotal.cs_nbfree;
8755a38b
KM
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);
993a756c
KM
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);
d4233021
KM
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 }
1a02fd3a
KM
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 }
d2c95d76 285 }
1a02fd3a
KM
286 zlnhead = (struct zlncnt *)0;
287 duplist = (struct dups *)0;
d2c95d76 288 if (dfile.mod) {
1a724405 289 (void)time(&sblock.fs_time);
d2c95d76
BJ
290 sbdirty();
291 }
292 ckfini();
293 free(blockmap);
d2c95d76 294 free(statemap);
1a724405 295 free((char *)lncntp);
addfa1aa
BJ
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);
f5971be7 306 }
f5971be7 307}
7718c0e6
KM
308
309char *
310blockcheck(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){
cfbff64d 319 perror("/");
7718c0e6
KM
320 printf("Can't stat root\n");
321 return (0);
322 }
323retry:
324 if (stat(name, &stblock) < 0){
cfbff64d 325 perror(name);
7718c0e6
KM
326 printf("Can't stat %s\n", name);
327 return (0);
328 }
e8c2f9ee 329 if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
cfbff64d
MK
330 if (stslash.st_dev == stblock.st_rdev) {
331 hotroot++;
332 return (name);
333 }
7718c0e6
KM
334 raw = rawname(name);
335 if (stat(raw, &stchar) < 0){
cfbff64d 336 perror(raw);
7718c0e6 337 printf("Can't stat %s\n", raw);
cfbff64d 338 return (name);
7718c0e6 339 }
cfbff64d 340 if ((stchar.st_mode & S_IFMT) == S_IFCHR)
7718c0e6 341 return (raw);
cfbff64d 342 else {
7718c0e6 343 printf("%s is not a character device\n", raw);
cfbff64d 344 return (name);
7718c0e6 345 }
e8c2f9ee 346 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR) {
7718c0e6
KM
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
359char *
360unrawname(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
378char *
379rawname(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}