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