arbitrarily cut off searching around orphaned directory loops
[unix-history] / usr / src / sbin / fsck / main.c
CommitLineData
fa95fc59 1#ifndef lint
7a187085 2char version[] = "@(#)main.c 2.30 (Berkeley) %G%";
fa95fc59 3#endif
07670f7d 4
6e884967
KM
5#include <stdio.h>
6#include <ctype.h>
4d308541
KM
7#include <sys/param.h>
8#include <sys/fs.h>
9#include <sys/inode.h>
4d308541 10#include <sys/stat.h>
1a724405 11#include <sys/wait.h>
6e884967 12#include <fstab.h>
1a724405
KM
13#define KERNEL
14#include <sys/dir.h>
15#undef KERNEL
6e884967 16
f5971be7
BJ
17/* RECONSTRUCT ONLY BAD CG IN PASS 6 */
18
6e884967
KM
19typedef int (*SIG_TYP)();
20
c312eebd
KM
21#define MAXNINDIR (MAXBSIZE / sizeof (daddr_t))
22#define MAXINOPB (MAXBSIZE / sizeof (struct dinode))
b6407c9d 23#define SPERB (MAXBSIZE / sizeof(short))
1a724405 24#define MINDIRSIZE (sizeof (struct dirtemplate))
6e884967
KM
25
26#define MAXDUP 10 /* limit on dup blks (per inode) */
27#define MAXBAD 10 /* limit on bad blks (per inode) */
28
29#define USTATE 0 /* inode not allocated */
30#define FSTATE 01 /* inode is file */
31#define DSTATE 02 /* inode is directory */
32#define CLEAR 03 /* inode is to be cleared */
33
34typedef struct dinode DINODE;
35typedef struct direct DIRECT;
36
37#define ALLOC ((dp->di_mode & IFMT) != 0)
24a31719 38#define DIRCT ((dp->di_mode & IFMT) == IFDIR)
6e884967
KM
39#define REG ((dp->di_mode & IFMT) == IFREG)
40#define BLK ((dp->di_mode & IFMT) == IFBLK)
41#define CHR ((dp->di_mode & IFMT) == IFCHR)
690f77ba 42#define LNK ((dp->di_mode & IFMT) == IFLNK)
af5ba2f8
KM
43#define SOCK ((dp->di_mode & IFMT) == IFSOCK)
44#define BADBLK ((dp->di_mode & IFMT) == IFMT)
ea47352d 45#define SPECIAL (BLK || CHR)
6e884967 46
6e884967
KM
47struct bufarea {
48 struct bufarea *b_next; /* must be first */
49 daddr_t b_bno;
50 int b_size;
51 union {
b6407c9d 52 char b_buf[MAXBSIZE]; /* buffer space */
6e884967 53 short b_lnks[SPERB]; /* link counts */
b6407c9d 54 daddr_t b_indir[MAXNINDIR]; /* indirect block */
6e884967
KM
55 struct fs b_fs; /* super block */
56 struct cg b_cg; /* cylinder group */
b6407c9d 57 struct dinode b_dinode[MAXINOPB]; /* inode block */
6e884967
KM
58 } b_un;
59 char b_dirty;
60};
61
62typedef struct bufarea BUFAREA;
63
64BUFAREA inoblk; /* inode blocks */
65BUFAREA fileblk; /* other blks in filesys */
66BUFAREA sblk; /* file system superblock */
1a724405 67BUFAREA cgblk; /* cylinder group blocks */
6e884967
KM
68
69#define initbarea(x) (x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
70#define dirty(x) (x)->b_dirty = 1
71#define inodirty() inoblk.b_dirty = 1
72#define sbdirty() sblk.b_dirty = 1
73#define cgdirty() cgblk.b_dirty = 1
74
75#define dirblk fileblk.b_un
76#define sblock sblk.b_un.b_fs
77#define cgrp cgblk.b_un.b_cg
78
79struct filecntl {
80 int rfdes;
81 int wfdes;
82 int mod;
83} dfile; /* file descriptors for filesys */
84
1a724405
KM
85struct inodesc {
86 char id_type; /* type of descriptor, DATA or ADDR */
87 int (*id_func)(); /* function to be applied to blocks of inode */
88 ino_t id_number; /* inode number described */
89 ino_t id_parent; /* for DATA nodes, their parent */
90 daddr_t id_blkno; /* current block number being examined */
91 int id_numfrags; /* number of frags contained in block */
92 long id_filesize; /* for DATA nodes, the size of the directory */
93 int id_loc; /* for DATA nodes, current location in dir */
94 int id_entryno; /* for DATA nodes, current entry number */
95 DIRECT *id_dirp; /* for data nodes, ptr to current entry */
96 enum {DONTKNOW, NOFIX, FIX} id_fix; /* policy on fixing errors */
97};
98/* file types */
99#define DATA 1
100#define ADDR 2
101
102
6e884967
KM
103#define DUPTBLSIZE 100 /* num of dup blocks to remember */
104daddr_t duplist[DUPTBLSIZE]; /* dup block table */
105daddr_t *enddup; /* next entry in dup table */
106daddr_t *muldup; /* multiple dups part of table */
107
5ca02310 108#define MAXLNCNT 500 /* num zero link cnts to remember */
6e884967
KM
109ino_t badlncnt[MAXLNCNT]; /* table of inos with zero link cnts */
110ino_t *badlnp; /* next entry in table */
111
112char rawflg;
113char nflag; /* assume a no response */
114char yflag; /* assume a yes response */
115int bflag; /* location of alternate super block */
6994bf5d 116int debug; /* output debugging info */
6e884967
KM
117char preen; /* just fix normal inconsistencies */
118char rplyflag; /* any questions asked? */
119char hotroot; /* checking root device */
120char fixcg; /* corrupted free list bit maps */
121
79f5f76a 122char *blockmap; /* ptr to primary blk allocation map */
6e884967
KM
123char *freemap; /* ptr to secondary blk allocation map */
124char *statemap; /* ptr to inode state table */
125short *lncntp; /* ptr to link count table */
126
6e884967 127char *srchname; /* name being searched for in dir */
1a724405
KM
128char pathname[BUFSIZ]; /* current pathname */
129char *pathp; /* pointer to pathname position */
aac37e2e 130char *endpathname = &pathname[BUFSIZ - 2];
6e884967
KM
131
132char *lfname = "lost+found";
133
6e884967 134ino_t imax; /* number of inodes */
6e884967
KM
135ino_t lastino; /* hiwater mark of inodes */
136ino_t lfdir; /* lost & found directory */
6e884967 137
6e884967 138off_t maxblk; /* largest logical blk in file */
79f5f76a 139off_t bmapsz; /* num chars in blockmap */
6e884967
KM
140
141daddr_t n_ffree; /* number of small free blocks */
142daddr_t n_bfree; /* number of large free blocks */
143daddr_t n_blks; /* number of blocks used */
144daddr_t n_files; /* number of files seen */
145daddr_t n_index;
146daddr_t n_bad;
147daddr_t fmax; /* number of blocks in the volume */
148
149daddr_t badblk;
150daddr_t dupblk;
151
152int inosumbad;
153int offsumbad;
f3c028b7 154int frsumbad;
184d432f 155int sbsumbad;
6e884967 156
6e884967
KM
157#define zapino(x) (*(x) = zino)
158struct dinode zino;
159
79f5f76a
KM
160#define setbmap(x) setbit(blockmap, x)
161#define getbmap(x) isset(blockmap, x)
162#define clrbmap(x) clrbit(blockmap, x)
6e884967
KM
163
164#define setfmap(x) setbit(freemap, x)
165#define getfmap(x) isset(freemap, x)
166#define clrfmap(x) clrbit(freemap, x)
167
1a724405 168#define ALTERED 010
6e884967
KM
169#define KEEPON 04
170#define SKIP 02
171#define STOP 01
172
173int (*signal())();
174long lseek();
175time_t time();
176DINODE *ginode();
1a724405 177DIRECT *fsck_readdir();
6e884967 178BUFAREA *getblk();
6e884967 179int catch();
1a724405
KM
180int findino(), mkentry(), chgdd();
181int pass1check(), pass1bcheck(), pass2check(), pass4check();
182char *rawname(), *unrawname();
183char *calloc(), *strcpy(), *strcat(), *rindex();
97656a89 184extern int inside[], around[];
b6407c9d 185extern unsigned char *fragtbl[];
6e884967
KM
186
187char *devname;
188
189main(argc, argv)
8ebf61ca
KM
190 int argc;
191 char *argv[];
6e884967
KM
192{
193 struct fstab *fsp;
194 int pid, passno, anygtr, sumstatus;
195
196 sync();
197 while (--argc > 0 && **++argv == '-') {
198 switch (*++*argv) {
199
200 case 'p':
201 preen++;
202 break;
203
204 case 'b':
1a724405
KM
205 if (argv[0][1] != '\0') {
206 bflag = atoi(argv[0]+1);
207 } else {
208 bflag = atoi(*++argv);
209 argc--;
210 }
6e884967
KM
211 printf("Alternate super block location: %d\n", bflag);
212 break;
213
6994bf5d
KM
214 case 'd':
215 debug++;
216 break;
217
6e884967
KM
218 case 'n': /* default no answer flag */
219 case 'N':
220 nflag++;
221 yflag = 0;
222 break;
223
224 case 'y': /* default yes answer flag */
225 case 'Y':
226 yflag++;
227 nflag = 0;
228 break;
229
230 default:
231 errexit("%c option?\n", **argv);
232 }
233 }
234 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1a724405 235 (void)signal(SIGINT, catch);
6e884967
KM
236 if (argc) {
237 while (argc-- > 0) {
238 hotroot = 0;
d2c95d76 239 checkfilesys(*argv++);
6e884967
KM
240 }
241 exit(0);
242 }
243 sumstatus = 0;
244 passno = 1;
245 do {
246 anygtr = 0;
247 if (setfsent() == 0)
248 errexit("Can't open checklist file: %s\n", FSTAB);
249 while ((fsp = getfsent()) != 0) {
250 if (strcmp(fsp->fs_type, FSTAB_RW) &&
fa95fc59
SL
251 strcmp(fsp->fs_type, FSTAB_RO) &&
252 strcmp(fsp->fs_type, FSTAB_RQ))
6e884967
KM
253 continue;
254 if (preen == 0 ||
255 passno == 1 && fsp->fs_passno == passno) {
256 if (blockcheck(fsp->fs_spec) == 0 && preen)
257 exit(8);
258 } else if (fsp->fs_passno > passno)
259 anygtr = 1;
260 else if (fsp->fs_passno == passno) {
261 pid = fork();
262 if (pid < 0) {
263 perror("fork");
264 exit(8);
265 }
266 if (pid == 0)
267 if (blockcheck(fsp->fs_spec)==0)
268 exit(8);
269 else
270 exit(0);
271 }
272 }
273 if (preen) {
1a724405 274 union wait status;
6e884967 275 while (wait(&status) != -1)
1a724405 276 sumstatus |= status.w_retcode;
6e884967
KM
277 }
278 passno++;
279 } while (anygtr);
280 if (sumstatus)
281 exit(8);
1a724405 282 (void)endfsent();
6e884967
KM
283 exit(0);
284}
285
286blockcheck(name)
287 char *name;
288{
4d308541 289 struct stat stslash, stblock, stchar;
6e884967
KM
290 char *raw;
291 int looped = 0;
292
293 hotroot = 0;
294 if (stat("/", &stslash) < 0){
295 error("Can't stat root\n");
296 return (0);
297 }
298retry:
299 if (stat(name, &stblock) < 0){
300 error("Can't stat %s\n", name);
301 return (0);
302 }
303 if (stblock.st_mode & S_IFBLK) {
304 raw = rawname(name);
305 if (stat(raw, &stchar) < 0){
306 error("Can't stat %s\n", raw);
307 return (0);
308 }
309 if (stchar.st_mode & S_IFCHR) {
310 if (stslash.st_dev == stblock.st_rdev) {
311 hotroot++;
addfa1aa 312 raw = unrawname(name);
6e884967 313 }
d2c95d76 314 checkfilesys(raw);
6e884967
KM
315 return (1);
316 } else {
317 error("%s is not a character device\n", raw);
318 return (0);
319 }
320 } else if (stblock.st_mode & S_IFCHR) {
321 if (looped) {
322 error("Can't make sense out of name %s\n", name);
323 return (0);
324 }
325 name = unrawname(name);
326 looped++;
327 goto retry;
328 }
329 error("Can't make sense out of name %s\n", name);
330 return (0);
331}
332
d2c95d76
BJ
333checkfilesys(filesys)
334 char *filesys;
6e884967 335{
6e884967 336
d2c95d76
BJ
337 devname = filesys;
338 if (setup(filesys) == 0) {
6e884967 339 if (preen)
d2c95d76 340 pfatal("CAN'T CHECK FILE SYSTEM.");
6e884967
KM
341 return;
342 }
d2c95d76 343/* 1: scan inodes tallying blocks used */
690f77ba
KM
344 if (preen == 0) {
345 printf("** Last Mounted on %s\n", sblock.fs_fsmnt);
6e884967
KM
346 if (hotroot)
347 printf("** Root file system\n");
348 printf("** Phase 1 - Check Blocks and Sizes\n");
349 }
d2c95d76
BJ
350 pass1();
351
f5971be7 352/* 1b: locate first references to duplicates, if any */
d2c95d76
BJ
353 if (enddup != &duplist[0]) {
354 if (preen)
355 pfatal("INTERNAL ERROR: dups with -p");
356 printf("** Phase 1b - Rescan For More DUPS\n");
357 pass1b();
358 }
359
1a724405 360/* 2: traverse directories from root to mark all connected directories */
d2c95d76
BJ
361 if (preen == 0)
362 printf("** Phase 2 - Check Pathnames\n");
363 pass2();
364
1a724405 365/* 3: scan inodes looking for disconnected directories */
d2c95d76
BJ
366 if (preen == 0)
367 printf("** Phase 3 - Check Connectivity\n");
368 pass3();
369
1a724405 370/* 4: scan inodes looking for disconnected files; check reference counts */
d2c95d76
BJ
371 if (preen == 0)
372 printf("** Phase 4 - Check Reference Counts\n");
373 pass4();
374
1a724405 375/* 5: check resource counts in cylinder groups */
d2c95d76
BJ
376 if (preen == 0)
377 printf("** Phase 5 - Check Cyl groups\n");
378 pass5();
379
380 if (fixcg) {
381 if (preen == 0)
382 printf("** Phase 6 - Salvage Cylinder Groups\n");
383 makecg();
384 n_ffree = sblock.fs_cstotal.cs_nffree;
385 n_bfree = sblock.fs_cstotal.cs_nbfree;
386 }
387
388 pwarn("%d files, %d used, %d free (%d frags, %d blocks)\n",
389 n_files, n_blks - howmany(sblock.fs_cssize, sblock.fs_fsize),
390 n_ffree + sblock.fs_frag * n_bfree, n_ffree, n_bfree);
391 if (dfile.mod) {
1a724405 392 (void)time(&sblock.fs_time);
d2c95d76
BJ
393 sbdirty();
394 }
395 ckfini();
396 free(blockmap);
397 free(freemap);
398 free(statemap);
1a724405 399 free((char *)lncntp);
addfa1aa
BJ
400 if (!dfile.mod)
401 return;
402 if (!preen) {
403 printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
404 if (hotroot)
405 printf("\n***** REBOOT UNIX *****\n");
406 }
407 if (hotroot) {
408 sync();
409 exit(4);
f5971be7 410 }
f5971be7
BJ
411}
412
413setup(dev)
414 char *dev;
415{
416 dev_t rootdev;
417 struct stat statb;
1a724405
KM
418 daddr_t super = bflag ? bflag : SBLOCK;
419 int i, j, c, d, cgd;
420 long size;
421 BUFAREA asblk;
422# define altsblock asblk.b_un.b_fs
f5971be7 423
f5971be7
BJ
424 if (stat("/", &statb) < 0)
425 errexit("Can't stat root\n");
426 rootdev = statb.st_dev;
427 if (stat(dev, &statb) < 0) {
428 error("Can't stat %s\n", dev);
429 return (0);
430 }
431 rawflg = 0;
432 if ((statb.st_mode & S_IFMT) == S_IFBLK)
433 ;
434 else if ((statb.st_mode & S_IFMT) == S_IFCHR)
435 rawflg++;
436 else {
437 if (reply("file is not a block or character device; OK") == 0)
438 return (0);
439 }
440 if (rootdev == statb.st_rdev)
441 hotroot++;
442 if ((dfile.rfdes = open(dev, 0)) < 0) {
443 error("Can't open %s\n", dev);
444 return (0);
445 }
446 if (preen == 0)
447 printf("** %s", dev);
448 if (nflag || (dfile.wfdes = open(dev, 1)) < 0) {
449 dfile.wfdes = -1;
450 if (preen)
451 pfatal("NO WRITE ACCESS");
452 printf(" (NO WRITE)");
453 }
454 if (preen == 0)
455 printf("\n");
456 fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; sbsumbad = 0;
457 dfile.mod = 0;
458 n_files = n_blks = n_ffree = n_bfree = 0;
459 muldup = enddup = &duplist[0];
460 badlnp = &badlncnt[0];
461 lfdir = 0;
462 rplyflag = 0;
463 initbarea(&sblk);
464 initbarea(&fileblk);
465 initbarea(&inoblk);
466 initbarea(&cgblk);
1a724405 467 initbarea(&asblk);
f5971be7
BJ
468 /*
469 * Read in the super block and its summary info.
470 */
1a724405 471 if (bread(&dfile, (char *)&sblock, super, (long)SBSIZE) == 0)
f5971be7
BJ
472 return (0);
473 sblk.b_bno = super;
474 sblk.b_size = SBSIZE;
475 /*
476 * run a few consistency checks of the super block
477 */
478 if (sblock.fs_magic != FS_MAGIC)
479 { badsb("MAGIC NUMBER WRONG"); return (0); }
480 if (sblock.fs_ncg < 1)
481 { badsb("NCG OUT OF RANGE"); return (0); }
482 if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
483 { badsb("CPG OUT OF RANGE"); return (0); }
f5971be7
BJ
484 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
485 (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
486 { badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
1a724405 487 if (sblock.fs_sbsize > SBSIZE)
f5971be7 488 { badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
1a724405
KM
489 /*
490 * Set all possible fields that could differ, then do check
491 * of whole super block against an alternate super block.
492 * When an alternate super-block is specified this check is skipped.
493 */
494 if (bflag)
495 goto sbok;
496 if (getblk(&asblk, cgsblock(&sblock, sblock.fs_ncg - 1),
497 sblock.fs_sbsize) == 0)
498 return (0);
499 altsblock.fs_link = sblock.fs_link;
500 altsblock.fs_rlink = sblock.fs_rlink;
501 altsblock.fs_time = sblock.fs_time;
502 altsblock.fs_cstotal = sblock.fs_cstotal;
503 altsblock.fs_cgrotor = sblock.fs_cgrotor;
504 altsblock.fs_fmod = sblock.fs_fmod;
505 altsblock.fs_clean = sblock.fs_clean;
506 altsblock.fs_ronly = sblock.fs_ronly;
507 altsblock.fs_flags = sblock.fs_flags;
508 altsblock.fs_maxcontig = sblock.fs_maxcontig;
509 altsblock.fs_minfree = sblock.fs_minfree;
510 altsblock.fs_rotdelay = sblock.fs_rotdelay;
511 altsblock.fs_maxbpg = sblock.fs_maxbpg;
512 bcopy((char *)sblock.fs_csp, (char *)altsblock.fs_csp,
513 sizeof sblock.fs_csp);
514 bcopy((char *)sblock.fs_fsmnt, (char *)altsblock.fs_fsmnt,
515 sizeof sblock.fs_fsmnt);
516 if (bcmp((char *)&sblock, (char *)&altsblock, (int)sblock.fs_sbsize))
517 { badsb("TRASHED VALUES IN SUPER BLOCK"); return (0); }
518sbok:
f5971be7
BJ
519 fmax = sblock.fs_size;
520 imax = sblock.fs_ncg * sblock.fs_ipg;
521 n_bad = cgsblock(&sblock, 0); /* boot block plus dedicated sblock */
522 /*
523 * read in the summary info.
524 */
525 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
526 size = sblock.fs_cssize - i < sblock.fs_bsize ?
527 sblock.fs_cssize - i : sblock.fs_bsize;
1a724405
KM
528 sblock.fs_csp[j] = (struct csum *)calloc(1, (unsigned)size);
529 if (bread(&dfile, (char *)sblock.fs_csp[j],
f5971be7 530 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
1a724405
KM
531 size) == 0)
532 return (0);
f5971be7
BJ
533 }
534 /*
535 * allocate and initialize the necessary maps
536 */
537 bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
1a724405 538 blockmap = calloc((unsigned)bmapsz, sizeof (char));
f5971be7
BJ
539 if (blockmap == NULL) {
540 printf("cannot alloc %d bytes for blockmap\n", bmapsz);
1a724405 541 goto badsb;
f5971be7 542 }
1a724405 543 freemap = calloc((unsigned)bmapsz, sizeof (char));
f5971be7
BJ
544 if (freemap == NULL) {
545 printf("cannot alloc %d bytes for freemap\n", bmapsz);
1a724405 546 goto badsb;
f5971be7 547 }
1a724405 548 statemap = calloc((unsigned)(imax + 1), sizeof(char));
f5971be7
BJ
549 if (statemap == NULL) {
550 printf("cannot alloc %d bytes for statemap\n", imax + 1);
1a724405 551 goto badsb;
f5971be7 552 }
1a724405 553 lncntp = (short *)calloc((unsigned)(imax + 1), sizeof(short));
f5971be7
BJ
554 if (lncntp == NULL) {
555 printf("cannot alloc %d bytes for lncntp\n",
556 (imax + 1) * sizeof(short));
1a724405 557 goto badsb;
f5971be7
BJ
558 }
559 for (c = 0; c < sblock.fs_ncg; c++) {
560 cgd = cgdmin(&sblock, c);
561 if (c == 0) {
562 d = cgbase(&sblock, c);
563 cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
564 } else
565 d = cgsblock(&sblock, c);
566 for (; d < cgd; d++)
567 setbmap(d);
568 }
569
f5971be7
BJ
570 return (1);
571
572badsb:
573 ckfini();
574 return (0);
1a724405 575# undef altsblock
d2c95d76
BJ
576}
577
578pass1()
579{
580 register int c, i, n, j;
581 register DINODE *dp;
1a724405
KM
582 int ndb, partial;
583 struct inodesc idesc;
584 ino_t inumber;
585
586 bzero((char *)&idesc, sizeof(struct inodesc));
587 idesc.id_type = ADDR;
588 idesc.id_func = pass1check;
589 inumber = 0;
bf541624 590 n_blks += howmany(sblock.fs_cssize, sblock.fs_fsize);
6e884967 591 for (c = 0; c < sblock.fs_ncg; c++) {
6994bf5d 592 if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
6e884967 593 continue;
f5971be7 594 if (cgrp.cg_magic != CG_MAGIC) {
1a724405
KM
595 pfatal("CG %d: BAD MAGIC NUMBER\n", c);
596 bzero((char *)&cgrp, (int)sblock.fs_cgsize);
f5971be7 597 }
6e884967 598 n = 0;
1a724405
KM
599 for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
600 dp = ginode(inumber);
f3c028b7
KM
601 if (dp == NULL)
602 continue;
bf4c734c 603 n++;
6e884967
KM
604 if (ALLOC) {
605 if (!isset(cgrp.cg_iused, i)) {
6994bf5d
KM
606 if (debug)
607 printf("%d bad, not used\n",
1a724405 608 inumber);
6e884967
KM
609 inosumbad++;
610 }
bf4c734c 611 n--;
1a724405 612 lastino = inumber;
af5ba2f8
KM
613 if (!preen && BADBLK &&
614 reply("HOLD BAD BLOCK") == 1) {
615 dp->di_size = sblock.fs_fsize;
616 dp->di_mode = IFREG|0600;
617 inodirty();
618 } else if (ftypeok(dp) == 0)
6bccc723 619 goto unknown;
67272100
KM
620 if (dp->di_size < 0) {
621 if (debug)
622 printf("bad size %d:",
623 dp->di_size);
6bccc723 624 goto unknown;
67272100 625 }
6bccc723
KM
626 ndb = howmany(dp->di_size, sblock.fs_bsize);
627 if (SPECIAL)
628 ndb++;
629 for (j = ndb; j < NDADDR; j++)
67272100
KM
630 if (dp->di_db[j] != 0) {
631 if (debug)
af5ba2f8
KM
632 printf("bad direct addr: %d\n",
633 dp->di_db[j]);
6bccc723 634 goto unknown;
67272100 635 }
6bccc723
KM
636 for (j = 0, ndb -= NDADDR; ndb > 0; j++)
637 ndb /= NINDIR(&sblock);
638 for (; j < NIADDR; j++)
67272100
KM
639 if (dp->di_ib[j] != 0) {
640 if (debug)
af5ba2f8
KM
641 printf("bad indirect addr: %d\n",
642 dp->di_ib[j]);
6bccc723 643 goto unknown;
67272100 644 }
6e884967 645 n_files++;
1a724405 646 lncntp[inumber] = dp->di_nlink;
f5262822 647 if (dp->di_nlink <= 0) {
6e884967 648 if (badlnp < &badlncnt[MAXLNCNT])
1a724405 649 *badlnp++ = inumber;
6e884967
KM
650 else {
651 pfatal("LINK COUNT TABLE OVERFLOW");
652 if (reply("CONTINUE") == 0)
653 errexit("");
654 }
655 }
1a724405
KM
656 statemap[inumber] = DIRCT ? DSTATE : FSTATE;
657 badblk = dupblk = 0; maxblk = 0;
658 idesc.id_number = inumber;
659 idesc.id_filesize = 0;
660 (void)ckinode(dp, &idesc);
661 idesc.id_filesize *= btodb(sblock.fs_fsize);
662 if (dp->di_blocks != idesc.id_filesize) {
5e01ca34 663 pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)",
1a724405
KM
664 inumber, dp->di_blocks,
665 idesc.id_filesize);
5e01ca34
KM
666 if (preen)
667 printf(" (CORRECTED)\n");
668 else if (reply("CORRECT") == 0)
669 continue;
1a724405 670 dp->di_blocks = idesc.id_filesize;
5e01ca34
KM
671 inodirty();
672 }
6bccc723
KM
673 continue;
674 unknown:
1a724405 675 pfatal("UNKNOWN FILE TYPE I=%u", inumber);
c10dd4b2 676 if (reply("CLEAR") == 1) {
6bccc723
KM
677 zapino(dp);
678 inodirty();
679 inosumbad++;
680 }
6e884967 681 } else {
6e884967 682 if (isset(cgrp.cg_iused, i)) {
6994bf5d
KM
683 if (debug)
684 printf("%d bad, marked used\n",
1a724405 685 inumber);
6e884967 686 inosumbad++;
f3c028b7 687 n--;
6e884967 688 }
6bccc723
KM
689 partial = 0;
690 for (j = 0; j < NDADDR; j++)
691 if (dp->di_db[j] != 0)
692 partial++;
693 for (j = 0; j < NIADDR; j++)
694 if (dp->di_ib[j] != 0)
695 partial++;
696 if (partial || dp->di_mode != 0 ||
697 dp->di_size != 0) {
1a724405
KM
698 pfatal("PARTIALLY ALLOCATED INODE I=%u",
699 inumber);
6e884967
KM
700 if (reply("CLEAR") == 1) {
701 zapino(dp);
702 inodirty();
703 inosumbad++;
704 }
705 }
706 }
707 }
0947395d 708 if (n != cgrp.cg_cs.cs_nifree) {
6994bf5d 709 if (debug)
bf4c734c 710 printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n",
6994bf5d 711 c, cgrp.cg_cs.cs_nifree, n);
6e884967
KM
712 inosumbad++;
713 }
184d432f
KM
714 if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree
715 || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree
716 || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree
717 || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir)
718 sbsumbad++;
6e884967 719 }
d2c95d76
BJ
720}
721
1a724405
KM
722pass1check(idesc)
723 register struct inodesc *idesc;
d2c95d76
BJ
724{
725 register daddr_t *dlp;
726 int res = KEEPON;
1a724405
KM
727 int anyout, nfrags;
728 daddr_t blkno = idesc->id_blkno;
d2c95d76 729
1a724405
KM
730 anyout = outrange(blkno, idesc->id_numfrags);
731 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
732 if (anyout && outrange(blkno, 1)) {
733 blkerr(idesc->id_number, "BAD", blkno);
d2c95d76 734 if (++badblk >= MAXBAD) {
1a724405
KM
735 pwarn("EXCESSIVE BAD BLKS I=%u",
736 idesc->id_number);
d2c95d76
BJ
737 if (preen)
738 printf(" (SKIPPING)\n");
739 else if (reply("CONTINUE") == 0)
740 errexit("");
741 return (STOP);
742 }
743 res = SKIP;
1a724405
KM
744 } else if (getbmap(blkno)) {
745 blkerr(idesc->id_number, "DUP", blkno);
d2c95d76 746 if (++dupblk >= MAXDUP) {
1a724405
KM
747 pwarn("EXCESSIVE DUP BLKS I=%u",
748 idesc->id_number);
d2c95d76
BJ
749 if (preen)
750 printf(" (SKIPPING)\n");
751 else if (reply("CONTINUE") == 0)
752 errexit("");
753 return (STOP);
754 }
755 if (enddup >= &duplist[DUPTBLSIZE]) {
756 pfatal("DUP TABLE OVERFLOW.");
757 if (reply("CONTINUE") == 0)
758 errexit("");
759 return (STOP);
760 }
761 for (dlp = duplist; dlp < muldup; dlp++)
1a724405
KM
762 if (*dlp == blkno) {
763 *enddup++ = blkno;
d2c95d76
BJ
764 break;
765 }
766 if (dlp >= muldup) {
767 *enddup++ = *muldup;
1a724405 768 *muldup++ = blkno;
f3c028b7 769 }
d2c95d76
BJ
770 } else {
771 n_blks++;
1a724405 772 setbmap(blkno);
d2c95d76 773 }
1a724405 774 idesc->id_filesize++;
d2c95d76
BJ
775 }
776 return (res);
777}
778
779pass1b()
780{
781 register int c, i;
782 register DINODE *dp;
1a724405
KM
783 struct inodesc idesc;
784 ino_t inumber;
d2c95d76 785
1a724405
KM
786 bzero((char *)&idesc, sizeof(struct inodesc));
787 idesc.id_type = ADDR;
788 idesc.id_func = pass1bcheck;
789 inumber = 0;
d2c95d76 790 for (c = 0; c < sblock.fs_ncg; c++) {
1a724405
KM
791 for (i = 0; i < sblock.fs_ipg; i++, inumber++) {
792 dp = ginode(inumber);
d2c95d76
BJ
793 if (dp == NULL)
794 continue;
1a724405
KM
795 idesc.id_number = inumber;
796 if (statemap[inumber] != USTATE &&
797 (ckinode(dp, &idesc) & STOP))
d2c95d76 798 goto out1b;
6e884967
KM
799 }
800 }
801out1b:
f3c028b7 802 flush(&dfile, &inoblk);
d2c95d76
BJ
803}
804
1a724405
KM
805pass1bcheck(idesc)
806 register struct inodesc *idesc;
d2c95d76
BJ
807{
808 register daddr_t *dlp;
1a724405
KM
809 int nfrags, res = KEEPON;
810 daddr_t blkno = idesc->id_blkno;
d2c95d76 811
1a724405
KM
812 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
813 if (outrange(blkno, 1))
d2c95d76
BJ
814 res = SKIP;
815 for (dlp = duplist; dlp < muldup; dlp++)
1a724405
KM
816 if (*dlp == blkno) {
817 blkerr(idesc->id_number, "DUP", blkno);
d2c95d76 818 *dlp = *--muldup;
1a724405 819 *muldup = blkno;
d2c95d76
BJ
820 if (muldup == duplist)
821 return (STOP);
822 }
823 }
824 return (res);
825}
826
827pass2()
828{
829 register DINODE *dp;
1a724405 830 struct inodesc rootdesc;
d2c95d76 831
1a724405
KM
832 bzero((char *)&rootdesc, sizeof(struct inodesc));
833 rootdesc.id_type = ADDR;
834 rootdesc.id_func = pass2check;
835 rootdesc.id_number = ROOTINO;
836 pathp = pathname;
837 switch (statemap[ROOTINO]) {
6e884967
KM
838
839 case USTATE:
840 errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
841
842 case FSTATE:
843 pfatal("ROOT INODE NOT DIRECTORY");
1a724405 844 if (reply("FIX") == 0 || (dp = ginode(ROOTINO)) == NULL)
6e884967
KM
845 errexit("");
846 dp->di_mode &= ~IFMT;
847 dp->di_mode |= IFDIR;
848 inodirty();
849 inosumbad++;
1a724405 850 statemap[ROOTINO] = DSTATE;
6e884967
KM
851 /* fall into ... */
852
853 case DSTATE:
1a724405 854 descend(&rootdesc, ROOTINO);
6e884967
KM
855 break;
856
857 case CLEAR:
858 pfatal("DUPS/BAD IN ROOT INODE");
859 printf("\n");
860 if (reply("CONTINUE") == 0)
861 errexit("");
1a724405
KM
862 statemap[ROOTINO] = DSTATE;
863 descend(&rootdesc, ROOTINO);
6e884967 864 }
d2c95d76
BJ
865}
866
1a724405
KM
867pass2check(idesc)
868 struct inodesc *idesc;
d2c95d76 869{
1a724405
KM
870 register DIRECT *dirp = idesc->id_dirp;
871 char *curpathloc;
872 int n, entrysize, ret = 0;
d2c95d76 873 DINODE *dp;
1a724405 874 DIRECT proto;
d2c95d76 875
1a724405
KM
876 /*
877 * check for "."
878 */
879 if (idesc->id_entryno != 0)
880 goto chk1;
881 if (dirp->d_ino != 0 && dirp->d_namlen == 1 && dirp->d_name[0] == '.') {
882 if (dirp->d_ino != idesc->id_number) {
883 direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'");
884 dirp->d_ino = idesc->id_number;
0104951b
KM
885 if (reply("FIX") == 1)
886 ret |= ALTERED;
1a724405
KM
887 }
888 goto chk1;
889 }
890 direrr(idesc->id_number, "MISSING '.'");
891 proto.d_ino = idesc->id_number;
892 proto.d_namlen = 1;
893 (void)strcpy(proto.d_name, ".");
894 entrysize = DIRSIZ(&proto);
895 if (dirp->d_ino != 0) {
896 pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n",
897 dirp->d_name);
898 } else if (dirp->d_reclen < entrysize) {
899 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n");
900 } else if (dirp->d_reclen < 2 * entrysize) {
901 proto.d_reclen = dirp->d_reclen;
902 bcopy((char *)&proto, (char *)dirp, entrysize);
0104951b
KM
903 if (reply("FIX") == 1)
904 ret |= ALTERED;
1a724405
KM
905 } else {
906 n = dirp->d_reclen - entrysize;
907 proto.d_reclen = entrysize;
908 bcopy((char *)&proto, (char *)dirp, entrysize);
909 idesc->id_entryno++;
910 lncntp[dirp->d_ino]--;
911 dirp = (DIRECT *)((char *)(dirp) + entrysize);
912 bzero((char *)dirp, n);
913 dirp->d_reclen = n;
0104951b
KM
914 if (reply("FIX") == 1)
915 ret |= ALTERED;
1a724405
KM
916 }
917chk1:
918 if (idesc->id_entryno > 1)
919 goto chk2;
920 proto.d_ino = idesc->id_parent;
921 proto.d_namlen = 2;
922 (void)strcpy(proto.d_name, "..");
923 entrysize = DIRSIZ(&proto);
924 if (idesc->id_entryno == 0) {
925 n = DIRSIZ(dirp);
926 if (dirp->d_reclen < n + entrysize)
927 goto chk2;
928 proto.d_reclen = dirp->d_reclen - n;
929 dirp->d_reclen = n;
930 idesc->id_entryno++;
931 lncntp[dirp->d_ino]--;
932 dirp = (DIRECT *)((char *)(dirp) + n);
933 bzero((char *)dirp, n);
934 dirp->d_reclen = n;
935 }
936 if (dirp->d_ino != 0 && dirp->d_namlen == 2 &&
937 strcmp(dirp->d_name, "..") == 0) {
938 if (dirp->d_ino != idesc->id_parent) {
939 direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'");
940 dirp->d_ino = idesc->id_parent;
0104951b
KM
941 if (reply("FIX") == 1)
942 ret |= ALTERED;
1a724405
KM
943 }
944 goto chk2;
945 }
946 direrr(idesc->id_number, "MISSING '..'");
947 if (dirp->d_ino != 0) {
948 pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n",
949 dirp->d_name);
950 } else if (dirp->d_reclen < entrysize) {
951 pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n");
952 } else {
953 proto.d_reclen = dirp->d_reclen;
954 bcopy((char *)&proto, (char *)dirp, entrysize);
0104951b
KM
955 if (reply("FIX") == 1)
956 ret |= ALTERED;
1a724405
KM
957 }
958chk2:
959 if (dirp->d_ino == 0)
960 return (ret|KEEPON);
961 if (idesc->id_entryno >= 2 &&
962 dirp->d_namlen <= 2 &&
963 dirp->d_name[0] == '.') {
964 if (dirp->d_namlen == 1) {
965 direrr(idesc->id_number, "EXTRA '.' ENTRY");
966 dirp->d_ino = 0;
0104951b
KM
967 if (reply("FIX") == 1)
968 ret |= ALTERED;
969 return (KEEPON | ret);
1a724405
KM
970 }
971 if (dirp->d_name[1] == '.') {
972 direrr(idesc->id_number, "EXTRA '..' ENTRY");
973 dirp->d_ino = 0;
0104951b
KM
974 if (reply("FIX") == 1)
975 ret |= ALTERED;
976 return (KEEPON | ret);
1a724405
KM
977 }
978 }
979 curpathloc = pathp;
980 *pathp++ = '/';
aac37e2e
KM
981 if (pathp + dirp->d_namlen >= endpathname) {
982 *pathp = '\0';
983 errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
984 }
1a724405
KM
985 bcopy(dirp->d_name, pathp, dirp->d_namlen + 1);
986 pathp += dirp->d_namlen;
987 idesc->id_entryno++;
d2c95d76 988 n = 0;
1a724405
KM
989 if (dirp->d_ino > imax || dirp->d_ino <= 0) {
990 direrr(dirp->d_ino, "I OUT OF RANGE");
991 n = reply("REMOVE");
992 } else {
d2c95d76 993again:
1a724405 994 switch (statemap[dirp->d_ino]) {
d2c95d76 995 case USTATE:
1a724405
KM
996 direrr(dirp->d_ino, "UNALLOCATED");
997 n = reply("REMOVE");
d2c95d76
BJ
998 break;
999
1000 case CLEAR:
1a724405
KM
1001 direrr(dirp->d_ino, "DUP/BAD");
1002 if ((n = reply("REMOVE")) == 1)
d2c95d76 1003 break;
1a724405 1004 if ((dp = ginode(dirp->d_ino)) == NULL)
d2c95d76 1005 break;
1a724405 1006 statemap[dirp->d_ino] = DIRCT ? DSTATE : FSTATE;
d2c95d76
BJ
1007 goto again;
1008
1009 case FSTATE:
1a724405 1010 lncntp[dirp->d_ino]--;
d2c95d76
BJ
1011 break;
1012
1013 case DSTATE:
1a724405
KM
1014 descend(idesc, dirp->d_ino);
1015 if (statemap[dirp->d_ino] != CLEAR) {
1016 lncntp[dirp->d_ino]--;
1017 } else {
1018 dirp->d_ino = 0;
1019 ret |= ALTERED;
1020 }
d2c95d76
BJ
1021 break;
1022 }
1023 }
1a724405
KM
1024 pathp = curpathloc;
1025 *pathp = '\0';
d2c95d76 1026 if (n == 0)
1a724405 1027 return (ret|KEEPON);
d2c95d76 1028 dirp->d_ino = 0;
1a724405 1029 return (ret|KEEPON|ALTERED);
d2c95d76
BJ
1030}
1031
1032pass3()
1033{
d2c95d76 1034 register DINODE *dp;
1a724405
KM
1035 struct inodesc idesc;
1036 ino_t inumber, orphan;
7a187085 1037 int loopcnt;
1a724405
KM
1038
1039 bzero((char *)&idesc, sizeof(struct inodesc));
1040 idesc.id_type = DATA;
1041 for (inumber = ROOTINO; inumber <= lastino; inumber++) {
1042 if (statemap[inumber] == DSTATE) {
bec6e7fb
KM
1043 pathp = pathname;
1044 *pathp++ = '?';
1045 *pathp = '\0';
1a724405 1046 idesc.id_func = findino;
6e884967 1047 srchname = "..";
1a724405 1048 idesc.id_parent = inumber;
7a187085 1049 loopcnt = 0;
6e884967 1050 do {
1a724405
KM
1051 orphan = idesc.id_parent;
1052 if ((dp = ginode(orphan)) == NULL)
6e884967 1053 break;
1a724405
KM
1054 idesc.id_parent = 0;
1055 idesc.id_filesize = dp->di_size;
1056 idesc.id_number = orphan;
1057 (void)ckinode(dp, &idesc);
1058 if (idesc.id_parent == 0)
6e884967 1059 break;
7a187085
KM
1060 if (loopcnt >= sblock.fs_cstotal.cs_ndir)
1061 break;
1062 loopcnt++;
1a724405
KM
1063 } while (statemap[idesc.id_parent] == DSTATE);
1064 if (linkup(orphan, idesc.id_parent) == 1) {
1a724405
KM
1065 idesc.id_func = pass2check;
1066 idesc.id_number = lfdir;
1067 descend(&idesc, orphan);
6e884967 1068 }
6e884967
KM
1069 }
1070 }
d2c95d76 1071}
6e884967 1072
d2c95d76
BJ
1073pass4()
1074{
1a724405
KM
1075 register ino_t inumber, *blp;
1076 int n;
1077 struct inodesc idesc;
d2c95d76 1078
1a724405
KM
1079 bzero((char *)&idesc, sizeof(struct inodesc));
1080 idesc.id_type = ADDR;
1081 idesc.id_func = pass4check;
1082 for (inumber = ROOTINO; inumber <= lastino; inumber++) {
1083 idesc.id_number = inumber;
1084 switch (statemap[inumber]) {
d2c95d76
BJ
1085
1086 case FSTATE:
1a724405 1087 n = lncntp[inumber];
f5262822 1088 if (n)
1a724405 1089 adjust(&idesc, (short)n);
6e884967
KM
1090 else {
1091 for (blp = badlncnt;blp < badlnp; blp++)
1a724405
KM
1092 if (*blp == inumber) {
1093 clri(&idesc, "UNREF", 1);
6e884967
KM
1094 break;
1095 }
1096 }
1097 break;
1098
1099 case DSTATE:
1a724405 1100 clri(&idesc, "UNREF", 1);
6e884967
KM
1101 break;
1102
1103 case CLEAR:
1a724405 1104 clri(&idesc, "BAD/DUP", 1);
6e884967
KM
1105 break;
1106 }
1107 }
8e5c1c7c 1108 if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) {
6e884967
KM
1109 pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
1110 if (preen)
1111 printf(" (FIXED)\n");
1112 if (preen || reply("FIX") == 1) {
bf4c734c 1113 sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files;
6e884967
KM
1114 sbdirty();
1115 }
1116 }
1117 flush(&dfile, &fileblk);
d2c95d76 1118}
6e884967 1119
1a724405
KM
1120pass4check(idesc)
1121 register struct inodesc *idesc;
d2c95d76
BJ
1122{
1123 register daddr_t *dlp;
1a724405
KM
1124 int nfrags, res = KEEPON;
1125 daddr_t blkno = idesc->id_blkno;
d2c95d76 1126
1a724405
KM
1127 for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
1128 if (outrange(blkno, 1))
d2c95d76 1129 res = SKIP;
1a724405 1130 else if (getbmap(blkno)) {
d2c95d76 1131 for (dlp = duplist; dlp < enddup; dlp++)
1a724405 1132 if (*dlp == blkno) {
d2c95d76
BJ
1133 *dlp = *--enddup;
1134 return (KEEPON);
1135 }
1a724405 1136 clrbmap(blkno);
d2c95d76
BJ
1137 n_blks--;
1138 }
1139 }
1140 return (res);
1141}
1142
1143pass5()
1144{
1145 register int c, n, i, b, d;
f5971be7
BJ
1146 short bo[MAXCPG][NRPOS];
1147 long botot[MAXCPG];
1148 long frsum[MAXFRAG];
1149 int blk;
1150 daddr_t cbase;
1151 int blockbits = (1<<sblock.fs_frag)-1;
d2c95d76 1152
0db712b3 1153 bcopy(blockmap, freemap, (unsigned)bmapsz);
6e884967 1154 dupblk = 0;
6994bf5d 1155 n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0));
6e884967 1156 for (c = 0; c < sblock.fs_ncg; c++) {
f5971be7 1157 cbase = cgbase(&sblock, c);
1a724405
KM
1158 bzero((char *)botot, sizeof (botot));
1159 bzero((char *)bo, sizeof (bo));
1160 bzero((char *)frsum, sizeof (frsum));
f3c028b7 1161 /*
bf541624 1162 * need to account for the super blocks
f3c028b7
KM
1163 * which appear (inaccurately) bad
1164 */
bf541624 1165 n_bad += cgtod(&sblock, c) - cgsblock(&sblock, c);
6994bf5d 1166 if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
6e884967 1167 continue;
f5971be7 1168 if (cgrp.cg_magic != CG_MAGIC) {
1a724405
KM
1169 pfatal("CG %d: BAD MAGIC NUMBER\n", c);
1170 bzero((char *)&cgrp, (int)sblock.fs_cgsize);
f5971be7 1171 }
b6407c9d 1172 for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
f5971be7
BJ
1173 blk = blkmap(&sblock, cgrp.cg_free, b);
1174 if (blk == 0)
1175 continue;
1176 if (blk == blockbits) {
d2c95d76 1177 if (pass5check(cbase+b, sblock.fs_frag) == STOP)
6e884967
KM
1178 goto out5;
1179 /* this is clumsy ... */
d2c95d76
BJ
1180 n_ffree -= sblock.fs_frag;
1181 n_bfree++;
1182 botot[cbtocylno(&sblock, b)]++;
1183 bo[cbtocylno(&sblock, b)]
1184 [cbtorpos(&sblock, b)]++;
f5971be7 1185 continue;
d2c95d76 1186 }
f5971be7
BJ
1187 for (d = 0; d < sblock.fs_frag; d++)
1188 if ((blk & (1<<d)) &&
1a724405 1189 pass5check(cbase + b + d, (long)1) == STOP)
f5971be7
BJ
1190 goto out5;
1191 fragacct(&sblock, blk, frsum, 1);
6e884967 1192 }
1a724405 1193 if (bcmp((char *)cgrp.cg_frsum, (char *)frsum, sizeof(frsum))) {
f5971be7
BJ
1194 if (debug)
1195 for (i = 0; i < sblock.fs_frag; i++)
1196 if (cgrp.cg_frsum[i] != frsum[i])
1197 printf("cg[%d].cg_frsum[%d] have %d calc %d\n",
1198 c, i, cgrp.cg_frsum[i], frsum[i]);
1199 frsumbad++;
d2c95d76 1200 }
1a724405 1201 if (bcmp((char *)cgrp.cg_btot, (char *)botot, sizeof (botot))) {
f5971be7
BJ
1202 if (debug)
1203 for (n = 0; n < sblock.fs_cpg; n++)
1204 if (botot[n] != cgrp.cg_btot[n])
1205 printf("cg[%d].cg_btot[%d] have %d calc %d\n",
1206 c, n, cgrp.cg_btot[n], botot[n]);
1207 offsumbad++;
1208 }
1a724405 1209 if (bcmp((char *)cgrp.cg_b, (char *)bo, sizeof (bo))) {
f5971be7 1210 if (debug)
d2c95d76 1211 for (i = 0; i < NRPOS; i++)
f5971be7
BJ
1212 if (bo[n][i] != cgrp.cg_b[n][i])
1213 printf("cg[%d].cg_b[%d][%d] have %d calc %d\n",
1214 c, n, i, cgrp.cg_b[n][i], bo[n][i]);
1215 offsumbad++;
6e884967
KM
1216 }
1217 }
d2c95d76
BJ
1218out5:
1219 if (dupblk)
1220 pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk);
1221 if (fixcg == 0) {
1222 if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) {
1223 pwarn("%ld BLK(S) MISSING\n", fmax - b);
1224 fixcg = 1;
1225 } else if (inosumbad + offsumbad + frsumbad + sbsumbad) {
1226 pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n",
1227 inosumbad ? "(INODE FREE) " : "",
1228 offsumbad ? "(BLOCK OFFSETS) " : "",
1229 frsumbad ? "(FRAG SUMMARIES) " : "",
1230 sbsumbad ? "(SUPER BLOCK SUMMARIES) " : "");
1231 fixcg = 1;
1232 } else if (n_ffree != sblock.fs_cstotal.cs_nffree ||
1233 n_bfree != sblock.fs_cstotal.cs_nbfree) {
1234 pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK");
1235 if (preen)
1236 printf(" (FIXED)\n");
1237 if (preen || reply("FIX") == 1) {
1238 sblock.fs_cstotal.cs_nffree = n_ffree;
1239 sblock.fs_cstotal.cs_nbfree = n_bfree;
1240 sbdirty();
1241 }
1242 }
1243 }
1244 if (fixcg) {
1245 pwarn("BAD CYLINDER GROUPS");
1246 if (preen)
1247 printf(" (SALVAGED)\n");
1248 else if (reply("SALVAGE") == 0)
1249 fixcg = 0;
1250 }
6e884967
KM
1251}
1252
d2c95d76 1253pass5check(blk, size)
6e884967 1254 daddr_t blk;
1a724405 1255 long size;
6e884967 1256{
6e884967 1257
1a724405 1258 if (outrange(blk, (int)size)) {
f5971be7
BJ
1259 fixcg = 1;
1260 if (preen)
1261 pfatal("BAD BLOCKS IN BIT MAPS.");
1262 if (++badblk >= MAXBAD) {
1263 printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
1264 if (reply("CONTINUE") == 0)
1265 errexit("");
1266 return (STOP);
1267 }
1268 }
1269 for (; size > 0; blk++, size--)
1270 if (getfmap(blk)) {
6e884967 1271 fixcg = 1;
7ebb5f4e 1272 ++dupblk;
6e884967
KM
1273 } else {
1274 n_ffree++;
1275 setfmap(blk);
1276 }
f5971be7 1277 return (KEEPON);
6e884967
KM
1278}
1279
1a724405 1280ckinode(dp, idesc)
d2c95d76 1281 DINODE *dp;
1a724405 1282 register struct inodesc *idesc;
d2c95d76
BJ
1283{
1284 register daddr_t *ap;
1a724405 1285 int ret, n, ndb, offset;
d2c95d76
BJ
1286 DINODE dino;
1287
1288 if (SPECIAL)
1289 return (KEEPON);
1290 dino = *dp;
1a724405
KM
1291 idesc->id_fix = DONTKNOW;
1292 idesc->id_entryno = 0;
d2c95d76
BJ
1293 ndb = howmany(dino.di_size, sblock.fs_bsize);
1294 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
1295 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
1a724405
KM
1296 idesc->id_numfrags =
1297 numfrags(&sblock, fragroundup(&sblock, offset));
d2c95d76 1298 else
1a724405
KM
1299 idesc->id_numfrags = sblock.fs_frag;
1300 if (*ap == 0)
1301 continue;
1302 idesc->id_blkno = *ap;
1303 if (idesc->id_type == ADDR)
1304 ret = (*idesc->id_func)(idesc);
1305 else
1306 ret = dirscan(idesc);
1307 if (ret & STOP)
d2c95d76
BJ
1308 return (ret);
1309 }
1a724405 1310 idesc->id_numfrags = sblock.fs_frag;
d2c95d76 1311 for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) {
d2c95d76 1312 if (*ap) {
1a724405
KM
1313 idesc->id_blkno = *ap;
1314 ret = iblock(idesc, n,
1315 dino.di_size - sblock.fs_bsize * NDADDR);
d2c95d76
BJ
1316 if (ret & STOP)
1317 return (ret);
1318 }
1319 }
1320 return (KEEPON);
1321}
1322
1a724405
KM
1323iblock(idesc, ilevel, isize)
1324 struct inodesc *idesc;
d2c95d76 1325 register ilevel;
1a724405 1326 long isize;
d2c95d76
BJ
1327{
1328 register daddr_t *ap;
1329 register daddr_t *aplim;
1a724405 1330 int i, n, (*func)(), nif;
d2c95d76
BJ
1331 BUFAREA ib;
1332
1a724405
KM
1333 if (idesc->id_type == ADDR) {
1334 func = idesc->id_func;
1335 if (((n = (*func)(idesc)) & KEEPON) == 0)
d2c95d76
BJ
1336 return (n);
1337 } else
1338 func = dirscan;
1a724405 1339 if (outrange(idesc->id_blkno, idesc->id_numfrags)) /* protect thyself */
d2c95d76
BJ
1340 return (SKIP);
1341 initbarea(&ib);
1a724405 1342 if (getblk(&ib, idesc->id_blkno, sblock.fs_bsize) == NULL)
d2c95d76
BJ
1343 return (SKIP);
1344 ilevel--;
1345 if (ilevel == 0) {
1346 nif = lblkno(&sblock, isize) + 1;
1347 } else /* ilevel == 1 */ {
1348 nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1;
1349 }
1350 if (nif > NINDIR(&sblock))
1351 nif = NINDIR(&sblock);
1352 aplim = &ib.b_un.b_indir[nif];
1353 for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
1354 if (*ap) {
1a724405 1355 idesc->id_blkno = *ap;
d2c95d76 1356 if (ilevel > 0)
1a724405 1357 n = iblock(idesc, ilevel,
d2c95d76
BJ
1358 isize - i*NINDIR(&sblock)*sblock.fs_bsize);
1359 else
1a724405 1360 n = (*func)(idesc);
d2c95d76
BJ
1361 if (n & STOP)
1362 return (n);
1363 }
1364 return (KEEPON);
1365}
1366
f5971be7 1367outrange(blk, cnt)
6e884967 1368 daddr_t blk;
f5971be7 1369 int cnt;
6e884967
KM
1370{
1371 register int c;
1372
f5971be7 1373 if ((unsigned)(blk+cnt) > fmax)
6e884967 1374 return (1);
f5971be7
BJ
1375 c = dtog(&sblock, blk);
1376 if (blk < cgdmin(&sblock, c)) {
1377 if ((blk+cnt) > cgsblock(&sblock, c)) {
1378 if (debug) {
1379 printf("blk %d < cgdmin %d;",
1380 blk, cgdmin(&sblock, c));
1381 printf(" blk+cnt %d > cgsbase %d\n",
1382 blk+cnt, cgsblock(&sblock, c));
1383 }
1384 return (1);
1385 }
1386 } else {
1387 if ((blk+cnt) > cgbase(&sblock, c+1)) {
1388 if (debug) {
1389 printf("blk %d >= cgdmin %d;",
1390 blk, cgdmin(&sblock, c));
1391 printf(" blk+cnt %d > sblock.fs_fpg %d\n",
1392 blk+cnt, sblock.fs_fpg);
1393 }
1394 return (1);
1395 }
07670f7d 1396 }
6e884967
KM
1397 return (0);
1398}
1399
1a724405
KM
1400blkerr(ino, s, blk)
1401 ino_t ino;
6e884967 1402 char *s;
1a724405 1403 daddr_t blk;
6e884967 1404{
f5262822 1405
1a724405 1406 pfatal("%ld %s I=%u", blk, s, ino);
6e884967 1407 printf("\n");
1a724405 1408 statemap[ino] = CLEAR;
6e884967
KM
1409}
1410
1a724405
KM
1411descend(parentino, inumber)
1412 struct inodesc *parentino;
1413 ino_t inumber;
6e884967
KM
1414{
1415 register DINODE *dp;
1a724405 1416 struct inodesc curino;
6e884967 1417
1a724405
KM
1418 bzero((char *)&curino, sizeof(struct inodesc));
1419 statemap[inumber] = FSTATE;
1420 if ((dp = ginode(inumber)) == NULL)
6e884967 1421 return;
1a724405
KM
1422 if (dp->di_size == 0) {
1423 direrr(inumber, "ZERO LENGTH DIRECTORY");
1424 if (reply("REMOVE") == 1)
1425 statemap[inumber] = CLEAR;
1426 return;
1427 }
1428 if (dp->di_size < MINDIRSIZE) {
1429 direrr(inumber, "DIRECTORY TOO SHORT");
1430 dp->di_size = MINDIRSIZE;
1431 if (reply("FIX") == 1)
1432 inodirty();
1433 }
1434 curino.id_type = DATA;
1435 curino.id_func = parentino->id_func;
1436 curino.id_parent = parentino->id_number;
1437 curino.id_number = inumber;
1438 curino.id_filesize = dp->di_size;
1439 (void)ckinode(dp, &curino);
6e884967
KM
1440}
1441
1a724405
KM
1442dirscan(idesc)
1443 register struct inodesc *idesc;
6e884967 1444{
24a31719 1445 register DIRECT *dp;
1a724405
KM
1446 int dsize, n;
1447 long blksiz;
754cadb5 1448 char dbuf[DIRBLKSIZ];
6e884967 1449
1a724405
KM
1450 if (idesc->id_type != DATA)
1451 errexit("wrong type to dirscan %d\n", idesc->id_type);
1452 blksiz = idesc->id_numfrags * sblock.fs_fsize;
1453 if (outrange(idesc->id_blkno, idesc->id_numfrags)) {
1454 idesc->id_filesize -= blksiz;
6e884967
KM
1455 return (SKIP);
1456 }
1a724405
KM
1457 idesc->id_loc = 0;
1458 for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
754cadb5 1459 dsize = dp->d_reclen;
1a724405
KM
1460 bcopy((char *)dp, dbuf, dsize);
1461 idesc->id_dirp = (DIRECT *)dbuf;
1462 if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
1463 if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) {
1464 bcopy(dbuf, (char *)dp, dsize);
8ebf61ca 1465 dirty(&fileblk);
6e884967
KM
1466 sbdirty();
1467 } else
1a724405 1468 n &= ~ALTERED;
6e884967 1469 }
24a31719 1470 if (n & STOP)
6e884967
KM
1471 return (n);
1472 }
1a724405 1473 return (idesc->id_filesize > 0 ? KEEPON : STOP);
6e884967
KM
1474}
1475
24a31719
KM
1476/*
1477 * get next entry in a directory.
1478 */
1479DIRECT *
1a724405
KM
1480fsck_readdir(idesc)
1481 register struct inodesc *idesc;
24a31719 1482{
754cadb5 1483 register DIRECT *dp, *ndp;
1a724405 1484 long size, blksiz;
24a31719 1485
1a724405
KM
1486 blksiz = idesc->id_numfrags * sblock.fs_fsize;
1487 if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) {
1488 idesc->id_filesize -= blksiz - idesc->id_loc;
24a31719
KM
1489 return NULL;
1490 }
1a724405
KM
1491 if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
1492 idesc->id_loc < blksiz) {
1493 dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
1494 if (dircheck(idesc, dp))
1495 goto dpok;
1496 idesc->id_loc += DIRBLKSIZ;
1497 idesc->id_filesize -= DIRBLKSIZ;
690f77ba
KM
1498 dp->d_reclen = DIRBLKSIZ;
1499 dp->d_ino = 0;
1500 dp->d_namlen = 0;
1a724405 1501 dp->d_name[0] = '\0';
1a724405
KM
1502 if (dofix(idesc))
1503 dirty(&fileblk);
1504 return (dp);
690f77ba 1505 }
1a724405
KM
1506dpok:
1507 if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
690f77ba 1508 return NULL;
1a724405
KM
1509 dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
1510 idesc->id_loc += dp->d_reclen;
1511 idesc->id_filesize -= dp->d_reclen;
1512 ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
1513 if ((idesc->id_filesize <= 0 && idesc->id_loc % DIRBLKSIZ != 0) ||
1514 (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
1515 dircheck(idesc, ndp) == 0)) {
1516 size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
1517 dp->d_reclen += size;
1518 idesc->id_loc += size;
1519 idesc->id_filesize -= size;
1a724405 1520 if (dofix(idesc))
690f77ba 1521 dirty(&fileblk);
24a31719 1522 }
690f77ba 1523 return (dp);
24a31719
KM
1524}
1525
1a724405
KM
1526/*
1527 * Verify that a directory entry is valid.
1528 * This is a superset of the checks made in the kernel.
1529 */
1530dircheck(idesc, dp)
1531 struct inodesc *idesc;
1532 register DIRECT *dp;
1533{
1534 register int size;
1535 register char *cp;
1536 int spaceleft;
1537
1538 size = DIRSIZ(dp);
1539 spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
1540 if (dp->d_ino < imax &&
1541 dp->d_reclen != 0 &&
1542 dp->d_reclen <= spaceleft &&
1543 (dp->d_reclen & 0x3) == 0 &&
1544 dp->d_reclen >= size &&
1545 idesc->id_filesize >= size &&
1546 dp->d_namlen <= MAXNAMLEN) {
1547 if (dp->d_ino == 0)
1548 return (1);
1549 for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++)
1550 if (*cp == 0 || (*cp++ & 0200))
1551 return (0);
1552 if (*cp == 0)
1553 return (1);
1554 }
1555 return (0);
1556}
1557
1558direrr(ino, s)
1559 ino_t ino;
8ebf61ca 1560 char *s;
6e884967
KM
1561{
1562 register DINODE *dp;
1563
1564 pwarn("%s ", s);
1a724405 1565 pinode(ino);
6e884967 1566 printf("\n");
1a724405
KM
1567 if ((dp = ginode(ino)) != NULL && ftypeok(dp))
1568 pfatal("%s=%s\n", DIRCT?"DIR":"FILE", pathname);
6e884967 1569 else
1a724405 1570 pfatal("NAME=%s\n", pathname);
6e884967
KM
1571}
1572
1a724405
KM
1573adjust(idesc, lcnt)
1574 register struct inodesc *idesc;
1575 short lcnt;
6e884967
KM
1576{
1577 register DINODE *dp;
1578
1a724405 1579 if ((dp = ginode(idesc->id_number)) == NULL)
6e884967
KM
1580 return;
1581 if (dp->di_nlink == lcnt) {
1a724405
KM
1582 if (linkup(idesc->id_number, (ino_t)0) == 0)
1583 clri(idesc, "UNREF", 0);
6e884967
KM
1584 }
1585 else {
1586 pwarn("LINK COUNT %s",
1a724405
KM
1587 (lfdir==idesc->id_number)?lfname:(DIRCT?"DIR":"FILE"));
1588 pinode(idesc->id_number);
6e884967
KM
1589 printf(" COUNT %d SHOULD BE %d",
1590 dp->di_nlink, dp->di_nlink-lcnt);
1591 if (preen) {
1592 if (lcnt < 0) {
1593 printf("\n");
1594 preendie();
1595 }
1596 printf(" (ADJUSTED)\n");
1597 }
1598 if (preen || reply("ADJUST") == 1) {
1599 dp->di_nlink -= lcnt;
1600 inodirty();
1601 }
1602 }
1603}
1604
1a724405
KM
1605clri(idesc, s, flg)
1606 register struct inodesc *idesc;
8ebf61ca 1607 char *s;
1a724405 1608 int flg;
6e884967
KM
1609{
1610 register DINODE *dp;
1611
1a724405 1612 if ((dp = ginode(idesc->id_number)) == NULL)
6e884967
KM
1613 return;
1614 if (flg == 1) {
24a31719 1615 pwarn("%s %s", s, DIRCT?"DIR":"FILE");
1a724405 1616 pinode(idesc->id_number);
6e884967
KM
1617 }
1618 if (preen || reply("CLEAR") == 1) {
1619 if (preen)
1620 printf(" (CLEARED)\n");
1621 n_files--;
1a724405 1622 (void)ckinode(dp, idesc);
6e884967 1623 zapino(dp);
1a724405 1624 statemap[idesc->id_number] = USTATE;
6e884967
KM
1625 inodirty();
1626 inosumbad++;
1627 }
1628}
1629
6e884967
KM
1630badsb(s)
1631 char *s;
1632{
1633
1634 if (preen)
1635 printf("%s: ", devname);
1636 printf("BAD SUPER BLOCK: %s\n", s);
1637 pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
1638 pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
1639}
1640
1641DINODE *
1a724405
KM
1642ginode(inumber)
1643 ino_t inumber;
6e884967
KM
1644{
1645 daddr_t iblk;
1a724405 1646 static ino_t startinum = 0; /* blk num of first in raw area */
6e884967 1647
1a724405
KM
1648
1649 if (inumber < ROOTINO || inumber > imax) {
1650 if (debug && inumber > imax)
1651 printf("inumber out of range (%d)\n", inumber);
6e884967 1652 return (NULL);
f3385032 1653 }
1a724405
KM
1654 if (startinum == 0 ||
1655 inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
1656 iblk = itod(&sblock, inumber);
b6407c9d 1657 if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
6e884967
KM
1658 return (NULL);
1659 }
1a724405 1660 startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
6e884967 1661 }
1a724405 1662 return (&inoblk.b_un.b_dinode[inumber % INOPB(&sblock)]);
6e884967
KM
1663}
1664
1665ftypeok(dp)
1666 DINODE *dp;
1667{
1668 switch (dp->di_mode & IFMT) {
1669
1670 case IFDIR:
1671 case IFREG:
1672 case IFBLK:
1673 case IFCHR:
ea47352d 1674 case IFLNK:
c10dd4b2 1675 case IFSOCK:
6e884967
KM
1676 return (1);
1677
1678 default:
67272100
KM
1679 if (debug)
1680 printf("bad file type 0%o\n", dp->di_mode);
6e884967
KM
1681 return (0);
1682 }
1683}
1684
1685reply(s)
1686 char *s;
1687{
1688 char line[80];
1689
1690 if (preen)
1691 pfatal("INTERNAL ERROR: GOT TO reply()");
1692 rplyflag = 1;
1693 printf("\n%s? ", s);
1694 if (nflag || dfile.wfdes < 0) {
1695 printf(" no\n\n");
1696 return (0);
1697 }
1698 if (yflag) {
1699 printf(" yes\n\n");
1700 return (1);
1701 }
1702 if (getline(stdin, line, sizeof(line)) == EOF)
1703 errexit("\n");
1704 printf("\n");
1705 if (line[0] == 'y' || line[0] == 'Y')
1706 return (1);
1707 else
1708 return (0);
1709}
1710
1711getline(fp, loc, maxlen)
1712 FILE *fp;
1713 char *loc;
1714{
1715 register n;
1716 register char *p, *lastloc;
1717
1718 p = loc;
1719 lastloc = &p[maxlen-1];
1720 while ((n = getc(fp)) != '\n') {
1721 if (n == EOF)
1722 return (EOF);
1723 if (!isspace(n) && p < lastloc)
1724 *p++ = n;
1725 }
1726 *p = 0;
1727 return (p - loc);
1728}
1729
1730BUFAREA *
1731getblk(bp, blk, size)
6e884967 1732 register BUFAREA *bp;
1a724405
KM
1733 daddr_t blk;
1734 long size;
6e884967
KM
1735{
1736 register struct filecntl *fcp;
b6407c9d 1737 daddr_t dblk;
6e884967
KM
1738
1739 fcp = &dfile;
b6407c9d
KM
1740 dblk = fsbtodb(&sblock, blk);
1741 if (bp->b_bno == dblk)
6e884967
KM
1742 return (bp);
1743 flush(fcp, bp);
b6407c9d
KM
1744 if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
1745 bp->b_bno = dblk;
6e884967
KM
1746 bp->b_size = size;
1747 return (bp);
1748 }
1749 bp->b_bno = (daddr_t)-1;
1750 return (NULL);
1751}
1752
1753flush(fcp, bp)
1754 struct filecntl *fcp;
1755 register BUFAREA *bp;
1756{
1757
1758 if (bp->b_dirty)
1a724405 1759 (void)bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
6e884967
KM
1760 bp->b_dirty = 0;
1761}
1762
1763rwerr(s, blk)
1764 char *s;
1765 daddr_t blk;
1766{
1767
1768 if (preen == 0)
1769 printf("\n");
1770 pfatal("CANNOT %s: BLK %ld", s, blk);
1771 if (reply("CONTINUE") == 0)
1772 errexit("Program terminated\n");
1773}
1774
1775ckfini()
1776{
1777
1778 flush(&dfile, &fileblk);
1779 flush(&dfile, &sblk);
f3c028b7
KM
1780 if (sblk.b_bno != SBLOCK) {
1781 sblk.b_bno = SBLOCK;
1782 sbdirty();
1783 flush(&dfile, &sblk);
1784 }
6e884967 1785 flush(&dfile, &inoblk);
1a724405
KM
1786 (void)close(dfile.rfdes);
1787 (void)close(dfile.wfdes);
6e884967
KM
1788}
1789
1a724405
KM
1790pinode(ino)
1791 ino_t ino;
6e884967
KM
1792{
1793 register DINODE *dp;
1794 register char *p;
24a31719 1795 char uidbuf[BUFSIZ];
6e884967
KM
1796 char *ctime();
1797
1a724405
KM
1798 printf(" I=%u ", ino);
1799 if ((dp = ginode(ino)) == NULL)
6e884967
KM
1800 return;
1801 printf(" OWNER=");
1802 if (getpw((int)dp->di_uid, uidbuf) == 0) {
1803 for (p = uidbuf; *p != ':'; p++);
1804 *p = 0;
1805 printf("%s ", uidbuf);
1806 }
1807 else {
1808 printf("%d ", dp->di_uid);
1809 }
1810 printf("MODE=%o\n", dp->di_mode);
1811 if (preen)
1812 printf("%s: ", devname);
1813 printf("SIZE=%ld ", dp->di_size);
1814 p = ctime(&dp->di_mtime);
1815 printf("MTIME=%12.12s %4.4s ", p+4, p+20);
1816}
1817
6e884967
KM
1818makecg()
1819{
f3c028b7 1820 int c, blk;
bf541624 1821 daddr_t dbase, d, dlower, dupper, dmax;
6e884967 1822 long i, j, s;
1a724405 1823 ino_t inumber;
6e884967 1824 register struct csum *cs;
f3c028b7 1825 register DINODE *dp;
6e884967 1826
0947395d
KM
1827 sblock.fs_cstotal.cs_nbfree = 0;
1828 sblock.fs_cstotal.cs_nffree = 0;
1829 sblock.fs_cstotal.cs_nifree = 0;
1830 sblock.fs_cstotal.cs_ndir = 0;
6e884967 1831 for (c = 0; c < sblock.fs_ncg; c++) {
6994bf5d 1832 dbase = cgbase(&sblock, c);
6e884967 1833 dmax = dbase + sblock.fs_fpg;
8f99f49c 1834 if (dmax > sblock.fs_size) {
bf4c734c 1835 for ( ; dmax >= sblock.fs_size; dmax--)
2e9860b5 1836 clrbit(cgrp.cg_free, dmax - dbase);
8f99f49c
KM
1837 dmax++;
1838 }
bf541624
KM
1839 dlower = cgsblock(&sblock, c) - dbase;
1840 dupper = cgdmin(&sblock, c) - dbase;
b6407c9d 1841 cs = &sblock.fs_cs(&sblock, c);
1a724405 1842 (void)time(&cgrp.cg_time);
6e884967
KM
1843 cgrp.cg_magic = CG_MAGIC;
1844 cgrp.cg_cgx = c;
67272100
KM
1845 if (c == sblock.fs_ncg - 1)
1846 cgrp.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
1847 else
1848 cgrp.cg_ncyl = sblock.fs_cpg;
6e884967
KM
1849 cgrp.cg_niblk = sblock.fs_ipg;
1850 cgrp.cg_ndblk = dmax - dbase;
0947395d
KM
1851 cgrp.cg_cs.cs_ndir = 0;
1852 cgrp.cg_cs.cs_nffree = 0;
1853 cgrp.cg_cs.cs_nbfree = 0;
1854 cgrp.cg_cs.cs_nifree = 0;
bf541624
KM
1855 cgrp.cg_rotor = 0;
1856 cgrp.cg_frotor = 0;
92ea6158 1857 cgrp.cg_irotor = 0;
b6407c9d 1858 for (i = 0; i < sblock.fs_frag; i++)
f3c028b7 1859 cgrp.cg_frsum[i] = 0;
1a724405
KM
1860 inumber = sblock.fs_ipg * c;
1861 for (i = 0; i < sblock.fs_ipg; inumber++, i++) {
bf4c734c
KM
1862 cgrp.cg_cs.cs_nifree++;
1863 clrbit(cgrp.cg_iused, i);
1a724405 1864 dp = ginode(inumber);
f3c028b7
KM
1865 if (dp == NULL)
1866 continue;
1867 if (ALLOC) {
24a31719 1868 if (DIRCT)
0947395d 1869 cgrp.cg_cs.cs_ndir++;
bf4c734c 1870 cgrp.cg_cs.cs_nifree--;
f3c028b7
KM
1871 setbit(cgrp.cg_iused, i);
1872 continue;
1873 }
6e884967
KM
1874 }
1875 while (i < MAXIPG) {
1876 clrbit(cgrp.cg_iused, i);
1877 i++;
1878 }
bf4c734c
KM
1879 if (c == 0)
1880 for (i = 0; i < ROOTINO; i++) {
1881 setbit(cgrp.cg_iused, i);
1882 cgrp.cg_cs.cs_nifree--;
1883 }
43f6367c
KM
1884 for (s = 0; s < MAXCPG; s++) {
1885 cgrp.cg_btot[s] = 0;
6e884967
KM
1886 for (i = 0; i < NRPOS; i++)
1887 cgrp.cg_b[s][i] = 0;
43f6367c 1888 }
6e884967 1889 if (c == 0) {
bf541624 1890 dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
6e884967 1891 }
bf541624 1892 for (d = dlower; d < dupper; d++)
6e884967 1893 clrbit(cgrp.cg_free, d);
bf541624
KM
1894 for (d = 0; (d + sblock.fs_frag) <= dmax - dbase;
1895 d += sblock.fs_frag) {
6e884967 1896 j = 0;
b6407c9d 1897 for (i = 0; i < sblock.fs_frag; i++) {
bf541624
KM
1898 if (!getbmap(dbase + d + i)) {
1899 setbit(cgrp.cg_free, d + i);
6e884967
KM
1900 j++;
1901 } else
1902 clrbit(cgrp.cg_free, d+i);
1903 }
b6407c9d 1904 if (j == sblock.fs_frag) {
0947395d 1905 cgrp.cg_cs.cs_nbfree++;
43f6367c 1906 cgrp.cg_btot[cbtocylno(&sblock, d)]++;
aca50d72
KM
1907 cgrp.cg_b[cbtocylno(&sblock, d)]
1908 [cbtorpos(&sblock, d)]++;
f3c028b7 1909 } else if (j > 0) {
0947395d 1910 cgrp.cg_cs.cs_nffree += j;
bf541624 1911 blk = blkmap(&sblock, cgrp.cg_free, d);
b6407c9d 1912 fragacct(&sblock, blk, cgrp.cg_frsum, 1);
f3c028b7 1913 }
6e884967 1914 }
f3c028b7 1915 for (j = d; d < dmax - dbase; d++) {
bf541624 1916 if (!getbmap(dbase + d)) {
6e884967 1917 setbit(cgrp.cg_free, d);
0947395d 1918 cgrp.cg_cs.cs_nffree++;
6e884967
KM
1919 } else
1920 clrbit(cgrp.cg_free, d);
1921 }
67272100
KM
1922 for (; d % sblock.fs_frag != 0; d++)
1923 clrbit(cgrp.cg_free, d);
f3c028b7 1924 if (j != d) {
bf541624 1925 blk = blkmap(&sblock, cgrp.cg_free, j);
b6407c9d 1926 fragacct(&sblock, blk, cgrp.cg_frsum, 1);
f3c028b7 1927 }
67272100
KM
1928 for (d /= sblock.fs_frag; d < MAXBPG(&sblock); d ++)
1929 clrblock(&sblock, cgrp.cg_free, d);
0947395d
KM
1930 sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree;
1931 sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree;
1932 sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
1933 sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
1934 *cs = cgrp.cg_cs;
1a724405
KM
1935 (void)bwrite(&dfile, (char *)&cgrp,
1936 fsbtodb(&sblock, cgtod(&sblock, c)), sblock.fs_cgsize);
6e884967 1937 }
bf541624 1938 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
1a724405 1939 (void)bwrite(&dfile, (char *)sblock.fs_csp[j],
bf541624
KM
1940 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
1941 sblock.fs_cssize - i < sblock.fs_bsize ?
1942 sblock.fs_cssize - i : sblock.fs_bsize);
c2a050cf 1943 }
6e884967
KM
1944 sblock.fs_ronly = 0;
1945 sblock.fs_fmod = 0;
1946 sbdirty();
1947}
1948
1a724405
KM
1949findino(idesc)
1950 struct inodesc *idesc;
6e884967 1951{
1a724405
KM
1952 register DIRECT *dirp = idesc->id_dirp;
1953
6e884967
KM
1954 if (dirp->d_ino == 0)
1955 return (KEEPON);
24a31719
KM
1956 if (!strcmp(dirp->d_name, srchname)) {
1957 if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
1a724405 1958 idesc->id_parent = dirp->d_ino;
24a31719 1959 return (STOP);
6e884967
KM
1960 }
1961 return (KEEPON);
1962}
1963
1a724405
KM
1964mkentry(idesc)
1965 struct inodesc *idesc;
6e884967 1966{
1a724405 1967 register DIRECT *dirp = idesc->id_dirp;
754cadb5
KM
1968 DIRECT newent;
1969 int newlen, oldlen;
6e884967 1970
754cadb5
KM
1971 newent.d_namlen = 11;
1972 newlen = DIRSIZ(&newent);
1973 if (dirp->d_ino != 0)
1974 oldlen = DIRSIZ(dirp);
1975 else
1976 oldlen = 0;
1977 if (dirp->d_reclen - oldlen < newlen)
6e884967 1978 return (KEEPON);
754cadb5
KM
1979 newent.d_reclen = dirp->d_reclen - oldlen;
1980 dirp->d_reclen = oldlen;
1981 dirp = (struct direct *)(((char *)dirp) + oldlen);
1a724405 1982 dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
754cadb5 1983 dirp->d_reclen = newent.d_reclen;
1a724405
KM
1984 dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent);
1985 return (ALTERED|STOP);
6e884967
KM
1986}
1987
1a724405
KM
1988chgdd(idesc)
1989 struct inodesc *idesc;
6e884967 1990{
1a724405
KM
1991 register DIRECT *dirp = idesc->id_dirp;
1992
6e884967
KM
1993 if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
1994 dirp->d_name[2] == 0) {
1995 dirp->d_ino = lfdir;
1a724405 1996 return (ALTERED|STOP);
6e884967
KM
1997 }
1998 return (KEEPON);
1999}
2000
1a724405
KM
2001linkup(orphan, pdir)
2002 ino_t orphan;
2003 ino_t pdir;
6e884967
KM
2004{
2005 register DINODE *dp;
bec6e7fb 2006 int lostdir, len;
1a724405 2007 struct inodesc idesc;
6e884967 2008
1a724405
KM
2009 bzero((char *)&idesc, sizeof(struct inodesc));
2010 if ((dp = ginode(orphan)) == NULL)
6e884967 2011 return (0);
24a31719 2012 lostdir = DIRCT;
6e884967 2013 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
1a724405 2014 pinode(orphan);
6e884967
KM
2015 if (preen && dp->di_size == 0)
2016 return (0);
2017 if (preen)
2018 printf(" (RECONNECTED)\n");
2019 else
2020 if (reply("RECONNECT") == 0)
2021 return (0);
bec6e7fb
KM
2022 pathp = pathname;
2023 *pathp++ = '/';
2024 *pathp = '\0';
6e884967 2025 if (lfdir == 0) {
1a724405 2026 if ((dp = ginode(ROOTINO)) == NULL)
6e884967 2027 return (0);
6e884967 2028 srchname = lfname;
1a724405
KM
2029 idesc.id_type = DATA;
2030 idesc.id_func = findino;
2031 idesc.id_number = ROOTINO;
2032 idesc.id_filesize = dp->di_size;
2033 (void)ckinode(dp, &idesc);
2034 if ((lfdir = idesc.id_parent) == 0) {
6e884967
KM
2035 pfatal("SORRY. NO lost+found DIRECTORY");
2036 printf("\n\n");
2037 return (0);
2038 }
2039 }
1a724405
KM
2040 if ((dp = ginode(lfdir)) == NULL ||
2041 !DIRCT || statemap[lfdir] != FSTATE) {
6e884967
KM
2042 pfatal("SORRY. NO lost+found DIRECTORY");
2043 printf("\n\n");
2044 return (0);
2045 }
3352e84a
KM
2046 if (fragoff(&sblock, dp->di_size)) {
2047 dp->di_size = fragroundup(&sblock, dp->di_size);
6e884967
KM
2048 inodirty();
2049 }
bec6e7fb
KM
2050 len = strlen(lfname);
2051 bcopy(lfname, pathp, len + 1);
2052 pathp += len;
1a724405
KM
2053 idesc.id_type = DATA;
2054 idesc.id_func = mkentry;
2055 idesc.id_number = lfdir;
2056 idesc.id_filesize = dp->di_size;
2057 idesc.id_parent = orphan; /* this is the inode to enter */
bec6e7fb 2058 idesc.id_fix = DONTKNOW;
1a724405 2059 if ((ckinode(dp, &idesc) & ALTERED) == 0) {
6e884967
KM
2060 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
2061 printf("\n\n");
2062 return (0);
2063 }
1a724405 2064 lncntp[orphan]--;
bec6e7fb
KM
2065 *pathp++ = '/';
2066 pathp += lftempname(pathp, orphan);
6e884967 2067 if (lostdir) {
1a724405
KM
2068 dp = ginode(orphan);
2069 idesc.id_type = DATA;
2070 idesc.id_func = chgdd;
2071 idesc.id_number = orphan;
2072 idesc.id_filesize = dp->di_size;
bec6e7fb 2073 idesc.id_fix = DONTKNOW;
1a724405
KM
2074 (void)ckinode(dp, &idesc);
2075 if ((dp = ginode(lfdir)) != NULL) {
6e884967
KM
2076 dp->di_nlink++;
2077 inodirty();
1a724405 2078 lncntp[lfdir]++;
6e884967 2079 }
6e884967
KM
2080 pwarn("DIR I=%u CONNECTED. ", orphan);
2081 printf("PARENT WAS I=%u\n", pdir);
2082 if (preen == 0)
2083 printf("\n");
2084 }
2085 return (1);
2086}
2087
1a724405
KM
2088/*
2089 * generate a temporary name for the lost+found directory.
2090 */
2091lftempname(bufp, ino)
2092 char *bufp;
2093 ino_t ino;
2094{
2095 register ino_t in;
2096 register char *cp;
2097 int namlen;
2098
2099 cp = bufp + 2;
2100 for (in = imax; in > 0; in /= 10)
2101 cp++;
2102 *--cp = 0;
2103 namlen = cp - bufp;
2104 in = ino;
2105 while (cp > bufp) {
2106 *--cp = (in % 10) + '0';
2107 in /= 10;
2108 }
2109 *cp = '#';
2110 return (namlen);
2111}
2112
6e884967 2113bread(fcp, buf, blk, size)
6e884967 2114 register struct filecntl *fcp;
6e884967 2115 char *buf;
1a724405
KM
2116 daddr_t blk;
2117 long size;
6e884967 2118{
1a724405 2119 if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
6e884967 2120 rwerr("SEEK", blk);
1a724405 2121 else if (read(fcp->rfdes, buf, (int)size) == size)
6e884967
KM
2122 return (1);
2123 rwerr("READ", blk);
2124 return (0);
2125}
2126
2127bwrite(fcp, buf, blk, size)
6e884967 2128 register struct filecntl *fcp;
6e884967 2129 char *buf;
1a724405
KM
2130 daddr_t blk;
2131 long size;
6e884967
KM
2132{
2133
2134 if (fcp->wfdes < 0)
2135 return (0);
1a724405 2136 if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
6e884967 2137 rwerr("SEEK", blk);
1a724405 2138 else if (write(fcp->wfdes, buf, (int)size) == size) {
6e884967
KM
2139 fcp->mod = 1;
2140 return (1);
2141 }
2142 rwerr("WRITE", blk);
2143 return (0);
2144}
2145
2146catch()
2147{
2148
2149 ckfini();
2150 exit(12);
2151}
b6407c9d 2152
d2c95d76
BJ
2153char *
2154unrawname(cp)
2155 char *cp;
2156{
2157 char *dp = rindex(cp, '/');
2158 struct stat stb;
2159
2160 if (dp == 0)
2161 return (cp);
2162 if (stat(cp, &stb) < 0)
2163 return (cp);
2164 if ((stb.st_mode&S_IFMT) != S_IFCHR)
2165 return (cp);
2166 if (*(dp+1) != 'r')
2167 return (cp);
1a724405 2168 (void)strcpy(dp+1, dp+2);
d2c95d76
BJ
2169 return (cp);
2170}
2171
2172char *
2173rawname(cp)
2174 char *cp;
2175{
2176 static char rawbuf[32];
2177 char *dp = rindex(cp, '/');
2178
2179 if (dp == 0)
2180 return (0);
2181 *dp = 0;
1a724405 2182 (void)strcpy(rawbuf, cp);
d2c95d76 2183 *dp = '/';
1a724405
KM
2184 (void)strcat(rawbuf, "/r");
2185 (void)strcat(rawbuf, dp+1);
d2c95d76
BJ
2186 return (rawbuf);
2187}
2188
1a724405
KM
2189/*
2190 * determine whether an inode should be fixed.
2191 */
2192dofix(idesc)
2193 register struct inodesc *idesc;
2194{
0104951b 2195
1a724405
KM
2196 switch (idesc->id_fix) {
2197
2198 case DONTKNOW:
0104951b
KM
2199 direrr(idesc->id_number, "DIRECTORY CORRUPTED");
2200 if (reply("SALVAGE") == 0) {
1a724405
KM
2201 idesc->id_fix = NOFIX;
2202 return (0);
2203 }
2204 idesc->id_fix = FIX;
2205 return (ALTERED);
2206
2207 case FIX:
2208 return (ALTERED);
2209
2210 case NOFIX:
2211 return (0);
2212
2213 default:
2214 errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
2215 }
2216 /* NOTREACHED */
2217}
2218
d2c95d76
BJ
2219/* VARARGS1 */
2220error(s1, s2, s3, s4)
2221 char *s1;
2222{
4d308541 2223
d2c95d76
BJ
2224 printf(s1, s2, s3, s4);
2225}
4d308541 2226
d2c95d76
BJ
2227/* VARARGS1 */
2228errexit(s1, s2, s3, s4)
2229 char *s1;
2230{
2231 error(s1, s2, s3, s4);
2232 exit(8);
2233}
4d308541
KM
2234
2235/*
d2c95d76 2236 * An inconsistency occured which shouldn't during normal operations.
af5ba2f8 2237 * Die if preening, otherwise just printf.
4d308541 2238 */
d2c95d76
BJ
2239/* VARARGS1 */
2240pfatal(s, a1, a2, a3)
2241 char *s;
2242{
4d308541 2243
d2c95d76
BJ
2244 if (preen) {
2245 printf("%s: ", devname);
2246 printf(s, a1, a2, a3);
2247 printf("\n");
2248 preendie();
2249 }
2250 printf(s, a1, a2, a3);
2251}
4d308541 2252
d2c95d76
BJ
2253preendie()
2254{
4d308541 2255
d2c95d76
BJ
2256 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
2257 exit(8);
2258}
4d308541
KM
2259
2260/*
d2c95d76
BJ
2261 * Pwarn is like printf when not preening,
2262 * or a warning (preceded by filename) when preening.
4d308541 2263 */
d2c95d76
BJ
2264/* VARARGS1 */
2265pwarn(s, a1, a2, a3, a4, a5, a6)
2266 char *s;
2267{
2268
2269 if (preen)
2270 printf("%s: ", devname);
2271 printf(s, a1, a2, a3, a4, a5, a6);
2272}
9a4020f4 2273
1a724405
KM
2274#ifndef lint
2275/*
2276 * Stub for routines from kernel.
2277 */
9a4020f4
BJ
2278panic(s)
2279 char *s;
2280{
2281
1a724405 2282 pfatal("INTERNAL INCONSISTENCY: %s\n", s);
9a4020f4
BJ
2283 exit(12);
2284}
1a724405 2285#endif