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