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