date and time created 90/02/01 14:32:02 by marc
[unix-history] / usr / src / sbin / fsck / main.c
CommitLineData
76797561 1/*
5eeaeb24 2 * Copyright (c) 1980, 1989 Regents of the University of California.
76797561
DF
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
7#ifndef lint
8char copyright[] =
5eeaeb24 9"@(#) Copyright (c) 1980, 1989 Regents of the University of California.\n\
76797561
DF
10 All rights reserved.\n";
11#endif not lint
12
fa95fc59 13#ifndef lint
72e5286b 14static char sccsid[] = "@(#)main.c 5.15 (Berkeley) %G%";
76797561 15#endif not lint
07670f7d 16
4d308541 17#include <sys/param.h>
72e5286b 18#include <ufs/dinode.h>
4d7f4685 19#include <ufs/fs.h>
7718c0e6
KM
20#include <sys/stat.h>
21#include <sys/wait.h>
22#include <fstab.h>
23#include <strings.h>
c689da7b 24#include <ctype.h>
f7635e39 25#include "fsck.h"
6e884967 26
5eeaeb24 27char *rawname(), *unrawname(), *blockcheck(), *malloc();
392fe950 28void catch(), catchquit(), voidquit();
3cfe4689 29int returntosingle;
7718c0e6 30
5eeaeb24
MK
31struct part {
32 char *name; /* device name */
33 char *fsname; /* mounted filesystem name */
34 struct part *next; /* forward link of partitions on disk */
35} *badlist, **badnext = &badlist;
36
37struct disk {
38 char *name; /* disk base name */
39 struct disk *next; /* forward link for list of disks */
40 struct part *part; /* head of list of partitions on disk */
41 int pid; /* If != 0, pid of proc working on */
42} *disks;
43
44int nrun, ndisks, maxrun;
45
7718c0e6
KM
46main(argc, argv)
47 int argc;
48 char *argv[];
49{
50 struct fstab *fsp;
5eeaeb24 51 int pid, passno, sumstatus;
7718c0e6 52 char *name;
5eeaeb24
MK
53 register struct disk *dk, *nextdisk;
54 register struct part *pt;
7718c0e6
KM
55
56 sync();
57 while (--argc > 0 && **++argv == '-') {
58 switch (*++*argv) {
59
60 case 'p':
61 preen++;
62 break;
63
64 case 'b':
65 if (argv[0][1] != '\0') {
66 bflag = atoi(argv[0]+1);
67 } else {
68 bflag = atoi(*++argv);
69 argc--;
70 }
71 printf("Alternate super block location: %d\n", bflag);
72 break;
73
d3e80ec3
KM
74 case 'c':
75 cvtflag++;
76 break;
77
7718c0e6
KM
78 case 'd':
79 debug++;
80 break;
81
5eeaeb24
MK
82 case 'l':
83 if (!isdigit(argv[1][0]))
84 errexit("-l flag requires a number\n");
85 maxrun = atoi(*++argv);
86 argc--;
87 break;
88
c689da7b
KM
89 case 'm':
90 if (!isdigit(argv[1][0]))
91 errexit("-m flag requires a mode\n");
92 sscanf(*++argv, "%o", &lfmode);
93 if (lfmode &~ 07777)
94 errexit("bad mode to -m: %o\n", lfmode);
95 argc--;
96 printf("** lost+found creation mode %o\n", lfmode);
97 break;
98
7718c0e6
KM
99 case 'n': /* default no answer flag */
100 case 'N':
101 nflag++;
102 yflag = 0;
103 break;
104
105 case 'y': /* default yes answer flag */
106 case 'Y':
107 yflag++;
108 nflag = 0;
109 break;
110
111 default:
112 errexit("%c option?\n", **argv);
113 }
114 }
115 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
116 (void)signal(SIGINT, catch);
3cfe4689
MK
117 if (preen)
118 (void)signal(SIGQUIT, catchquit);
7718c0e6
KM
119 if (argc) {
120 while (argc-- > 0) {
121 hotroot = 0;
cfbff64d 122 checkfilesys(*argv++);
7718c0e6
KM
123 }
124 exit(0);
125 }
126 sumstatus = 0;
5eeaeb24 127 for (passno = 1; passno <= 2; passno++) {
7718c0e6 128 if (setfsent() == 0)
4d7f4685 129 errexit("Can't open checklist file: %s\n", _PATH_FSTAB);
7718c0e6
KM
130 while ((fsp = getfsent()) != 0) {
131 if (strcmp(fsp->fs_type, FSTAB_RW) &&
132 strcmp(fsp->fs_type, FSTAB_RO) &&
133 strcmp(fsp->fs_type, FSTAB_RQ))
134 continue;
135 if (preen == 0 ||
5eeaeb24 136 passno == 1 && fsp->fs_passno == 1) {
7718c0e6
KM
137 name = blockcheck(fsp->fs_spec);
138 if (name != NULL)
139 checkfilesys(name);
140 else if (preen)
141 exit(8);
5eeaeb24 142 } else if (passno == 2 && fsp->fs_passno > 1) {
844eeb65
KM
143 name = blockcheck(fsp->fs_spec);
144 if (name == NULL) {
145 pwarn("BAD DISK NAME %s\n",
146 fsp->fs_spec);
147 sumstatus |= 8;
148 continue;
149 }
5eeaeb24 150 addpart(name, fsp->fs_file);
7718c0e6
KM
151 }
152 }
5eeaeb24
MK
153 }
154 if (preen) {
155 union wait status;
156
157 if (maxrun == 0)
158 maxrun = ndisks;
159 if (maxrun > ndisks)
160 maxrun = ndisks;
161 nextdisk = disks;
162 for (passno = 0; passno < maxrun; ++passno) {
163 startdisk(nextdisk);
164 nextdisk = nextdisk->next;
165 }
166 while ((pid = wait(&status)) != -1) {
5eeaeb24
MK
167 for (dk = disks; dk; dk = dk->next)
168 if (dk->pid == pid)
169 break;
170 if (dk == 0) {
171 printf("Unknown pid %d\n", pid);
172 continue;
173 }
174 if (status.w_termsig) {
175 printf("%s (%s): EXITED WITH SIGNAL %d\n",
176 dk->part->name, dk->part->fsname,
177 status.w_termsig);
178 status.w_retcode = 8;
179 }
180 if (status.w_retcode != 0) {
08f28b2a 181 sumstatus |= status.w_retcode;
5eeaeb24
MK
182 *badnext = dk->part;
183 badnext = &dk->part->next;
184 dk->part = dk->part->next;
185 *badnext = NULL;
186 } else
187 dk->part = dk->part->next;
188 dk->pid = 0;
189 nrun--;
190 if (dk->part == NULL)
191 ndisks--;
192
193 if (nextdisk == NULL) {
194 if (dk->part)
195 startdisk(dk);
196 } else if (nrun < maxrun && nrun < ndisks) {
197 for ( ;; ) {
198 if ((nextdisk = nextdisk->next) == NULL)
199 nextdisk = disks;
200 if (nextdisk->part != NULL &&
201 nextdisk->pid == 0)
844eeb65 202 break;
844eeb65 203 }
5eeaeb24 204 startdisk(nextdisk);
844eeb65 205 }
7718c0e6 206 }
5eeaeb24 207 }
844eeb65
KM
208 if (sumstatus) {
209 if (badlist == 0)
210 exit(8);
211 printf("THE FOLLOWING FILE SYSTEM%s HAD AN %s\n\t",
212 badlist->next ? "S" : "", "UNEXPECTED INCONSISTENCY:");
5eeaeb24
MK
213 for (pt = badlist; pt; pt = pt->next)
214 printf("%s (%s)%s", pt->name, pt->fsname,
215 pt->next ? ", " : "\n");
7718c0e6 216 exit(8);
844eeb65 217 }
7718c0e6 218 (void)endfsent();
3cfe4689
MK
219 if (returntosingle)
220 exit(2);
7718c0e6
KM
221 exit(0);
222}
223
5eeaeb24
MK
224struct disk *
225finddisk(name)
226 char *name;
227{
228 register struct disk *dk, **dkp;
229 register char *p;
230 int len;
231
232 for (p = name + strlen(name) - 1; p >= name; --p)
233 if (isdigit(*p)) {
234 len = p - name + 1;
235 break;
236 }
237 if (p < name)
238 len = strlen(name);
239
240 for (dk = disks, dkp = &disks; dk; dkp = &dk->next, dk = dk->next) {
241 if (strncmp(dk->name, name, len) == 0 &&
242 dk->name[len] == 0)
243 return (dk);
244 }
245 if ((*dkp = (struct disk *)malloc(sizeof(struct disk))) == NULL)
246 errexit("out of memory");
247 dk = *dkp;
248 if ((dk->name = malloc(len + 1)) == NULL)
249 errexit("out of memory");
250 strncpy(dk->name, name, len);
251 dk->name[len] = '\0';
252 dk->part = NULL;
253 dk->next = NULL;
254 dk->pid = 0;
255 ndisks++;
256 return (dk);
257}
258
259addpart(name, fsname)
260 char *name, *fsname;
261{
262 struct disk *dk = finddisk(name);
263 register struct part *pt, **ppt = &dk->part;
264
265 for (pt = dk->part; pt; ppt = &pt->next, pt = pt->next)
266 if (strcmp(pt->name, name) == 0) {
267 printf("%s in fstab more than once!\n", name);
268 return;
269 }
270 if ((*ppt = (struct part *)malloc(sizeof(struct part))) == NULL)
271 errexit("out of memory");
272 pt = *ppt;
273 if ((pt->name = malloc(strlen(name) + 1)) == NULL)
274 errexit("out of memory");
275 strcpy(pt->name, name);
276 if ((pt->fsname = malloc(strlen(fsname) + 1)) == NULL)
277 errexit("out of memory");
278 strcpy(pt->fsname, fsname);
279 pt->next = NULL;
280}
281
282startdisk(dk)
283 register struct disk *dk;
284{
285
286 nrun++;
287 dk->pid = fork();
288 if (dk->pid < 0) {
289 perror("fork");
290 exit(8);
291 }
292 if (dk->pid == 0) {
293 (void)signal(SIGQUIT, voidquit);
294 checkfilesys(dk->part->name);
295 exit(0);
296 }
297}
298
d2c95d76
BJ
299checkfilesys(filesys)
300 char *filesys;
6e884967 301{
993a756c 302 daddr_t n_ffree, n_bfree;
d4233021 303 struct dups *dp;
1a02fd3a 304 struct zlncnt *zlnp;
6e884967 305
d2c95d76 306 devname = filesys;
5eeaeb24
MK
307 if (debug && preen)
308 pwarn("starting\n");
d2c95d76 309 if (setup(filesys) == 0) {
6e884967 310 if (preen)
d2c95d76 311 pfatal("CAN'T CHECK FILE SYSTEM.");
6e884967
KM
312 return;
313 }
993a756c
KM
314 /*
315 * 1: scan inodes tallying blocks used
316 */
690f77ba
KM
317 if (preen == 0) {
318 printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
6e884967
KM
319 if (hotroot)
320 printf("** Root file system\n");
321 printf("** Phase 1 - Check Blocks and Sizes\n");
322 }
d2c95d76
BJ
323 pass1();
324
993a756c
KM
325 /*
326 * 1b: locate first references to duplicates, if any
327 */
62e6c152 328 if (duplist) {
d2c95d76
BJ
329 if (preen)
330 pfatal("INTERNAL ERROR: dups with -p");
331 printf("** Phase 1b - Rescan For More DUPS\n");
332 pass1b();
333 }
334
993a756c
KM
335 /*
336 * 2: traverse directories from root to mark all connected directories
337 */
d2c95d76
BJ
338 if (preen == 0)
339 printf("** Phase 2 - Check Pathnames\n");
340 pass2();
341
993a756c
KM
342 /*
343 * 3: scan inodes looking for disconnected directories
344 */
d2c95d76
BJ
345 if (preen == 0)
346 printf("** Phase 3 - Check Connectivity\n");
347 pass3();
348
993a756c
KM
349 /*
350 * 4: scan inodes looking for disconnected files; check reference counts
351 */
d2c95d76
BJ
352 if (preen == 0)
353 printf("** Phase 4 - Check Reference Counts\n");
354 pass4();
355
993a756c
KM
356 /*
357 * 5: check and repair resource counts in cylinder groups
358 */
d2c95d76
BJ
359 if (preen == 0)
360 printf("** Phase 5 - Check Cyl groups\n");
361 pass5();
362
993a756c
KM
363 /*
364 * print out summary statistics
365 */
366 n_ffree = sblock.fs_cstotal.cs_nffree;
367 n_bfree = sblock.fs_cstotal.cs_nbfree;
8755a38b
KM
368 pwarn("%d files, %d used, %d free ",
369 n_files, n_blks, n_ffree + sblock.fs_frag * n_bfree);
370 printf("(%d frags, %d blocks, %.1f%% fragmentation)\n",
371 n_ffree, n_bfree, (float)(n_ffree * 100) / sblock.fs_dsize);
993a756c
KM
372 if (debug && (n_files -= imax - ROOTINO - sblock.fs_cstotal.cs_nifree))
373 printf("%d files missing\n", n_files);
374 if (debug) {
375 n_blks += sblock.fs_ncg *
376 (cgdmin(&sblock, 0) - cgsblock(&sblock, 0));
377 n_blks += cgsblock(&sblock, 0) - cgbase(&sblock, 0);
378 n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
379 if (n_blks -= fmax - (n_ffree + sblock.fs_frag * n_bfree))
380 printf("%d blocks missing\n", n_blks);
d4233021
KM
381 if (duplist != NULL) {
382 printf("The following duplicate blocks remain:");
383 for (dp = duplist; dp; dp = dp->next)
384 printf(" %d,", dp->dup);
385 printf("\n");
386 }
1a02fd3a
KM
387 if (zlnhead != NULL) {
388 printf("The following zero link count inodes remain:");
389 for (zlnp = zlnhead; zlnp; zlnp = zlnp->next)
390 printf(" %d,", zlnp->zlncnt);
391 printf("\n");
392 }
d2c95d76 393 }
1a02fd3a
KM
394 zlnhead = (struct zlncnt *)0;
395 duplist = (struct dups *)0;
d2c95d76 396 if (dfile.mod) {
1a724405 397 (void)time(&sblock.fs_time);
d2c95d76
BJ
398 sbdirty();
399 }
400 ckfini();
401 free(blockmap);
d2c95d76 402 free(statemap);
1a724405 403 free((char *)lncntp);
addfa1aa
BJ
404 if (!dfile.mod)
405 return;
406 if (!preen) {
407 printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
408 if (hotroot)
409 printf("\n***** REBOOT UNIX *****\n");
410 }
411 if (hotroot) {
412 sync();
413 exit(4);
f5971be7 414 }
f5971be7 415}
7718c0e6
KM
416
417char *
418blockcheck(name)
419 char *name;
420{
421 struct stat stslash, stblock, stchar;
422 char *raw;
423 int looped = 0;
424
425 hotroot = 0;
426 if (stat("/", &stslash) < 0){
cfbff64d 427 perror("/");
7718c0e6
KM
428 printf("Can't stat root\n");
429 return (0);
430 }
431retry:
432 if (stat(name, &stblock) < 0){
cfbff64d 433 perror(name);
7718c0e6
KM
434 printf("Can't stat %s\n", name);
435 return (0);
436 }
e8c2f9ee 437 if ((stblock.st_mode & S_IFMT) == S_IFBLK) {
cfbff64d
MK
438 if (stslash.st_dev == stblock.st_rdev) {
439 hotroot++;
440 return (name);
441 }
7718c0e6
KM
442 raw = rawname(name);
443 if (stat(raw, &stchar) < 0){
cfbff64d 444 perror(raw);
7718c0e6 445 printf("Can't stat %s\n", raw);
cfbff64d 446 return (name);
7718c0e6 447 }
cfbff64d 448 if ((stchar.st_mode & S_IFMT) == S_IFCHR)
7718c0e6 449 return (raw);
cfbff64d 450 else {
7718c0e6 451 printf("%s is not a character device\n", raw);
cfbff64d 452 return (name);
7718c0e6 453 }
e8c2f9ee 454 } else if ((stblock.st_mode & S_IFMT) == S_IFCHR) {
7718c0e6
KM
455 if (looped) {
456 printf("Can't make sense out of name %s\n", name);
457 return (0);
458 }
459 name = unrawname(name);
460 looped++;
461 goto retry;
462 }
463 printf("Can't make sense out of name %s\n", name);
464 return (0);
465}
466
467char *
468unrawname(cp)
469 char *cp;
470{
471 char *dp = rindex(cp, '/');
472 struct stat stb;
473
474 if (dp == 0)
475 return (cp);
476 if (stat(cp, &stb) < 0)
477 return (cp);
478 if ((stb.st_mode&S_IFMT) != S_IFCHR)
479 return (cp);
480 if (*(dp+1) != 'r')
481 return (cp);
482 (void)strcpy(dp+1, dp+2);
483 return (cp);
484}
485
486char *
487rawname(cp)
488 char *cp;
489{
490 static char rawbuf[32];
491 char *dp = rindex(cp, '/');
492
493 if (dp == 0)
494 return (0);
495 *dp = 0;
496 (void)strcpy(rawbuf, cp);
497 *dp = '/';
498 (void)strcat(rawbuf, "/r");
499 (void)strcat(rawbuf, dp+1);
500 return (rawbuf);
501}