Commit | Line | Data |
---|---|---|
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 | |
8 | char 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 |
844eeb65 | 14 | static char sccsid[] = "@(#)main.c 5.8 (Berkeley) %G%"; |
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 | 26 | char *rawname(), *unrawname(), *blockcheck(); |
3cfe4689 MK |
27 | int catch(), catchquit(), voidquit(); |
28 | int returntosingle; | |
7718c0e6 KM |
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; | |
844eeb65 KM |
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); | |
844eeb65 KM |
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; | |
844eeb65 | 153 | while ((pid = wait(&status)) != -1) { |
7718c0e6 | 154 | sumstatus |= status.w_retcode; |
844eeb65 KM |
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 | } | |
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:"); | |
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 |
193 | checkfilesys(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 | |
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){ | |
cfbff64d | 319 | perror("/"); |
7718c0e6 KM |
320 | printf("Can't stat root\n"); |
321 | return (0); | |
322 | } | |
323 | retry: | |
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 | ||
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 | } |