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