force reboot after fixing the root file system
[unix-history] / usr / src / sbin / fsck / main.c
CommitLineData
b54b8079 1static char sccsid[] = "@(#)main.c 2.9 (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
KM
732 if (dfile.mod)
733 if (preen)
734 printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
735 else if (hotroot) {
736 printf("\n***** BOOT UNIX (NO SYNC!) *****\n");
737 exit(4);
738 }
739 sync();
6e884967
KM
740}
741
742/* VARARGS1 */
743error(s1, s2, s3, s4)
8ebf61ca 744 char *s1;
6e884967
KM
745{
746
747 printf(s1, s2, s3, s4);
748}
749
750/* VARARGS1 */
751errexit(s1, s2, s3, s4)
8ebf61ca 752 char *s1;
6e884967
KM
753{
754 error(s1, s2, s3, s4);
755 exit(8);
756}
757
758/*
759 * An inconsistency occured which shouldn't during normal operations.
760 * Die if preening, otw just printf.
761 */
762/* VARARGS1 */
763pfatal(s, a1, a2, a3)
764 char *s;
765{
766
767 if (preen) {
768 printf("%s: ", devname);
769 printf(s, a1, a2, a3);
770 printf("\n");
771 preendie();
772 }
773 printf(s, a1, a2, a3);
774}
775
776preendie()
777{
778
779 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
780 exit(8);
781}
782
783/*
784 * Pwarn is like printf when not preening,
785 * or a warning (preceded by filename) when preening.
786 */
787/* VARARGS1 */
690f77ba 788pwarn(s, a1, a2, a3, a4, a5, a6)
6e884967
KM
789 char *s;
790{
791
792 if (preen)
793 printf("%s: ", devname);
690f77ba 794 printf(s, a1, a2, a3, a4, a5, a6);
6e884967
KM
795}
796
797ckinode(dp, flg)
798 DINODE *dp;
799 register flg;
800{
801 register daddr_t *ap;
802 register ret;
3352e84a 803 int (*func)(), n, ndb, size, offset;
6c6be8f1
KM
804 ino_t number = inum;
805 DINODE dino;
6e884967
KM
806
807 if (SPECIAL)
808 return (KEEPON);
6c6be8f1 809 dino = *dp;
6e884967 810 func = (flg == ADDR) ? pfunc : dirscan;
6c6be8f1
KM
811 ndb = howmany(dino.di_size, sblock.fs_bsize);
812 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
813 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
3352e84a 814 size = numfrags(&sblock, fragroundup(&sblock, offset));
6e884967 815 else
b6407c9d 816 size = sblock.fs_frag;
6c6be8f1 817 dnum = number;
6e884967
KM
818 if (*ap && (ret = (*func)(*ap, size)) & STOP)
819 return (ret);
820 }
6c6be8f1
KM
821 for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) {
822 dnum = number;
823 if (*ap && (ret = iblock(*ap, n, flg, dino.di_size - sblock.fs_bsize * NDADDR)) & STOP)
6e884967 824 return (ret);
6e884967
KM
825 }
826 return (KEEPON);
827}
828
829iblock(blk, ilevel, flg, isize)
830 daddr_t blk;
831 register ilevel;
832 int isize;
833{
834 register daddr_t *ap;
835 register daddr_t *aplim;
07670f7d 836 register int i, n;
6e884967
KM
837 int (*func)(), nif;
838 BUFAREA ib;
839
6e884967
KM
840 if (flg == ADDR) {
841 func = pfunc;
b6407c9d 842 if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0)
6e884967
KM
843 return (n);
844 } else
845 func = dirscan;
846 if (outrange(blk)) /* protect thyself */
847 return (SKIP);
848 initbarea(&ib);
b6407c9d 849 if (getblk(&ib, blk, sblock.fs_bsize) == NULL)
6e884967
KM
850 return (SKIP);
851 ilevel--;
07670f7d 852 if (ilevel == 0) {
3352e84a 853 nif = lblkno(&sblock, isize) + 1;
07670f7d 854 } else /* ilevel == 1 */ {
b6407c9d 855 nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1;
07670f7d 856 }
b6407c9d
KM
857 if (nif > NINDIR(&sblock))
858 nif = NINDIR(&sblock);
07670f7d
KM
859 aplim = & ib.b_un.b_indir[nif];
860 for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
6e884967
KM
861 if (*ap) {
862 if (ilevel > 0)
b6407c9d 863 n = iblock(*ap, ilevel, flg, isize - i * NINDIR(&sblock) * sblock.fs_bsize);
6e884967 864 else
b6407c9d 865 n = (*func)(*ap, sblock.fs_frag);
6e884967
KM
866 if (n & STOP)
867 return (n);
868 }
869 return (KEEPON);
870}
871
872pass1(blk, size)
873 daddr_t blk;
874 int size;
875{
876 register daddr_t *dlp;
877 int res = KEEPON;
878
879 for (; size > 0; blk++, size--) {
880 if (outrange(blk)) {
881 blkerr("BAD", blk);
882 if (++badblk >= MAXBAD) {
883 printf("EXCESSIVE BAD BLKS I=%u", inum);
884 if (reply("CONTINUE") == 0)
885 errexit("");
886 return (STOP);
887 }
888 res = SKIP;
889 } else if (getbmap(blk)) {
890 blkerr("DUP", blk);
891 if (++dupblk >= MAXDUP) {
892 printf("EXCESSIVE DUP BLKS I=%u", inum);
893 if (reply("CONTINUE") == 0)
894 errexit("");
895 return (STOP);
896 }
897 if (enddup >= &duplist[DUPTBLSIZE]) {
898 printf("DUP TABLE OVERFLOW.");
899 if (reply("CONTINUE") == 0)
900 errexit("");
901 return (STOP);
902 }
903 for (dlp = duplist; dlp < muldup; dlp++)
904 if (*dlp == blk) {
905 *enddup++ = blk;
906 break;
907 }
908 if (dlp >= muldup) {
909 *enddup++ = *muldup;
910 *muldup++ = blk;
911 }
912 } else {
913 n_blks++;
914 setbmap(blk);
915 }
916 filsize++;
917 }
918 return (res);
919}
920
921pass1b(blk, size)
922 daddr_t blk;
923 int size;
924{
925 register daddr_t *dlp;
926 int res = KEEPON;
927
928 for (; size > 0; blk++, size--) {
929 if (outrange(blk))
930 res = SKIP;
931 for (dlp = duplist; dlp < muldup; dlp++)
932 if (*dlp == blk) {
933 blkerr("DUP", blk);
934 *dlp = *--muldup;
935 *muldup = blk;
936 if (muldup == duplist)
937 return (STOP);
938 }
939 }
940 return (res);
941}
942
943pass2(dirp)
944 register DIRECT *dirp;
945{
946 register char *p;
947 register n;
948 DINODE *dp;
949
950 if ((inum = dirp->d_ino) == 0)
951 return (KEEPON);
952 thisname = pathp;
24a31719 953 for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; )
6e884967
KM
954 if ((*pathp++ = *p++) == 0) {
955 --pathp;
956 break;
957 }
958 *pathp = 0;
959 n = 0;
8ebf61ca 960 if (inum > imax || inum <= 0)
6e884967
KM
961 n = direrr("I OUT OF RANGE");
962 else {
963again:
964 switch (getstate()) {
965 case USTATE:
966 n = direrr("UNALLOCATED");
967 break;
968
969 case CLEAR:
970 if ((n = direrr("DUP/BAD")) == 1)
971 break;
972 if ((dp = ginode()) == NULL)
973 break;
24a31719 974 setstate(DIRCT ? DSTATE : FSTATE);
6e884967
KM
975 goto again;
976
977 case FSTATE:
978 declncnt();
979 break;
980
981 case DSTATE:
982 declncnt();
983 descend();
984 break;
985 }
986 }
987 pathp = thisname;
988 if (n == 0)
989 return (KEEPON);
990 dirp->d_ino = 0;
991 return (KEEPON|ALTERD);
992}
993
994pass4(blk, size)
8ebf61ca 995 daddr_t blk;
6e884967
KM
996{
997 register daddr_t *dlp;
998 int res = KEEPON;
999
1000 for (; size > 0; blk++, size--) {
1001 if (outrange(blk))
1002 res = SKIP;
1003 else if (getbmap(blk)) {
1004 for (dlp = duplist; dlp < enddup; dlp++)
1005 if (*dlp == blk) {
1006 *dlp = *--enddup;
1007 return (KEEPON);
1008 }
1009 clrbmap(blk);
1010 n_blks--;
1011 }
1012 }
1013 return (res);
1014}
1015
1016pass5(blk, size)
1017 daddr_t blk;
1018 int size;
1019{
1020 int res = KEEPON;
1021
1022 for (; size > 0; blk++, size--) {
1023 if (outrange(blk)) {
1024 fixcg = 1;
1025 if (preen)
1026 pfatal("BAD BLOCKS IN BIT MAPS.");
1027 if (++badblk >= MAXBAD) {
1028 printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
1029 if (reply("CONTINUE") == 0)
1030 errexit("");
1031 return (STOP);
1032 }
1033 } else if (getfmap(blk)) {
1034 fixcg = 1;
1035 if (++dupblk >= DUPTBLSIZE) {
1036 printf("EXCESSIVE DUP BLKS IN BIT MAPS.");
1037 if (reply("CONTINUE") == 0)
1038 errexit("");
1039 return (STOP);
1040 }
1041 } else {
1042 n_ffree++;
1043 setfmap(blk);
1044 }
1045 }
1046 return (res);
1047}
1048
1049outrange(blk)
1050 daddr_t blk;
1051{
1052 register int c;
1053
6994bf5d 1054 c = dtog(&sblock, blk);
bf541624 1055 if ((unsigned)blk >= fmax) {
6e884967 1056 return (1);
07670f7d 1057 }
6e884967
KM
1058 return (0);
1059}
1060
1061blkerr(s, blk)
1062 daddr_t blk;
1063 char *s;
1064{
1065 pfatal("%ld %s I=%u", blk, s, inum);
1066 printf("\n");
1067 setstate(CLEAR); /* mark for possible clearing */
1068}
1069
1070descend()
1071{
1072 register DINODE *dp;
1073 register char *savname;
1074 off_t savsize;
1075
1076 setstate(FSTATE);
1077 if ((dp = ginode()) == NULL)
1078 return;
1079 savname = thisname;
1080 *pathp++ = '/';
1081 savsize = filsize;
1082 filsize = dp->di_size;
1083 ckinode(dp, DATA);
1084 thisname = savname;
1085 *--pathp = 0;
1086 filsize = savsize;
1087}
1088
24a31719
KM
1089struct dirstuff {
1090 int loc;
1091 int blkno;
1092 int blksiz;
6c6be8f1 1093 ino_t number;
cf8ac751 1094 enum {DONTKNOW, NOFIX, FIX} fix;
24a31719
KM
1095};
1096
6e884967 1097dirscan(blk, nf)
8ebf61ca
KM
1098 daddr_t blk;
1099 int nf;
6e884967 1100{
24a31719 1101 register DIRECT *dp;
24a31719 1102 struct dirstuff dirp;
754cadb5
KM
1103 int blksiz, dsize, n;
1104 char dbuf[DIRBLKSIZ];
6e884967
KM
1105
1106 if (outrange(blk)) {
b6407c9d 1107 filsize -= sblock.fs_bsize;
6e884967
KM
1108 return (SKIP);
1109 }
24a31719
KM
1110 blksiz = nf * sblock.fs_fsize;
1111 dirp.loc = 0;
1112 dirp.blkno = blk;
1113 dirp.blksiz = blksiz;
690f77ba
KM
1114 if (dirp.number != dnum) {
1115 dirp.number = dnum;
cf8ac751 1116 dirp.fix = DONTKNOW;
690f77ba 1117 }
24a31719 1118 for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
754cadb5
KM
1119 dsize = dp->d_reclen;
1120 copy(dp, dbuf, dsize);
1121 if ((n = (*pfunc)(dbuf)) & ALTERD) {
24a31719 1122 if (getblk(&fileblk, blk, blksiz) != NULL) {
754cadb5 1123 copy(dbuf, dp, dsize);
8ebf61ca 1124 dirty(&fileblk);
6e884967
KM
1125 sbdirty();
1126 } else
1127 n &= ~ALTERD;
1128 }
24a31719 1129 if (n & STOP)
6e884967
KM
1130 return (n);
1131 }
1132 return (filsize > 0 ? KEEPON : STOP);
1133}
1134
24a31719
KM
1135/*
1136 * get next entry in a directory.
1137 */
1138DIRECT *
1139readdir(dirp)
1140 register struct dirstuff *dirp;
1141{
754cadb5 1142 register DIRECT *dp, *ndp;
690f77ba 1143 long size;
24a31719
KM
1144
1145 if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) {
1146 filsize -= dirp->blksiz - dirp->loc;
1147 return NULL;
1148 }
690f77ba
KM
1149 while (dirp->loc % DIRBLKSIZ == 0 && filsize > 0 &&
1150 dirp->loc < dirp->blksiz) {
052efd62 1151 dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
690f77ba
KM
1152 if (dp->d_ino < imax &&
1153 dp->d_namlen <= MAXNAMLEN && dp->d_namlen >= 0 &&
1154 dp->d_reclen > 0 && dp->d_reclen <= DIRBLKSIZ)
1155 break;
1156 dirp->loc += DIRBLKSIZ;
1157 filsize -= DIRBLKSIZ;
cf8ac751 1158 if (dirp->fix == DONTKNOW) {
6c6be8f1 1159 pwarn("DIRECTORY %D CORRUPTED", dirp->number);
cf8ac751 1160 dirp->fix = NOFIX;
690f77ba 1161 if (preen) {
754cadb5 1162 printf(" (SALVAGED)\n");
cf8ac751 1163 dirp->fix = FIX;
690f77ba 1164 } else if (reply("SALVAGE") != 0)
cf8ac751 1165 dirp->fix = FIX;
690f77ba 1166 }
cf8ac751 1167 if (dirp->fix != FIX)
24a31719 1168 continue;
690f77ba
KM
1169 dp->d_reclen = DIRBLKSIZ;
1170 dp->d_ino = 0;
1171 dp->d_namlen = 0;
1172 dirty(&fileblk);
1173 }
1174 if (filsize <= 0 || dirp->loc >= dirp->blksiz)
1175 return NULL;
1176 dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
1177 dirp->loc += dp->d_reclen;
1178 filsize -= dp->d_reclen;
1179 ndp = (DIRECT *)(dirblk.b_buf + dirp->loc);
1180 if (dirp->loc < dirp->blksiz && filsize > 0 &&
1181 (ndp->d_ino >= imax ||
1182 ndp->d_namlen > MAXNAMLEN || ndp->d_namlen < 0 ||
1183 ndp->d_reclen <= 0 ||
1184 ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ))) {
1185 size = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
1186 dirp->loc += size;
1187 filsize -= size;
cf8ac751 1188 if (dirp->fix == DONTKNOW) {
690f77ba 1189 pwarn("DIRECTORY %D CORRUPTED", dirp->number);
cf8ac751 1190 dirp->fix = NOFIX;
690f77ba
KM
1191 if (preen) {
1192 printf(" (SALVAGED)\n");
cf8ac751 1193 dirp->fix = FIX;
690f77ba 1194 } else if (reply("SALVAGE") != 0)
cf8ac751 1195 dirp->fix = FIX;
690f77ba 1196 }
cf8ac751 1197 if (dirp->fix == FIX) {
690f77ba
KM
1198 dp->d_reclen += size;
1199 dirty(&fileblk);
754cadb5 1200 }
24a31719 1201 }
690f77ba 1202 return (dp);
24a31719
KM
1203}
1204
6e884967 1205direrr(s)
8ebf61ca 1206 char *s;
6e884967
KM
1207{
1208 register DINODE *dp;
1209
1210 pwarn("%s ", s);
1211 pinode();
1212 printf("\n");
1213 if ((dp = ginode()) != NULL && ftypeok(dp))
24a31719 1214 pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname);
6e884967
KM
1215 else
1216 pfatal("NAME=%s", pathname);
1217 return (reply("REMOVE"));
1218}
1219
1220adjust(lcnt)
f3c028b7 1221 register short lcnt;
6e884967
KM
1222{
1223 register DINODE *dp;
1224
1225 if ((dp = ginode()) == NULL)
1226 return;
1227 if (dp->di_nlink == lcnt) {
1228 if (linkup() == 0)
1229 clri("UNREF", 0);
1230 }
1231 else {
1232 pwarn("LINK COUNT %s",
24a31719 1233 (lfdir==inum)?lfname:(DIRCT?"DIR":"FILE"));
6e884967
KM
1234 pinode();
1235 printf(" COUNT %d SHOULD BE %d",
1236 dp->di_nlink, dp->di_nlink-lcnt);
1237 if (preen) {
1238 if (lcnt < 0) {
1239 printf("\n");
1240 preendie();
1241 }
1242 printf(" (ADJUSTED)\n");
1243 }
1244 if (preen || reply("ADJUST") == 1) {
1245 dp->di_nlink -= lcnt;
1246 inodirty();
1247 }
1248 }
1249}
1250
1251clri(s, flg)
8ebf61ca 1252 char *s;
6e884967
KM
1253{
1254 register DINODE *dp;
1255
1256 if ((dp = ginode()) == NULL)
1257 return;
1258 if (flg == 1) {
24a31719 1259 pwarn("%s %s", s, DIRCT?"DIR":"FILE");
6e884967
KM
1260 pinode();
1261 }
1262 if (preen || reply("CLEAR") == 1) {
1263 if (preen)
1264 printf(" (CLEARED)\n");
1265 n_files--;
1266 pfunc = pass4;
1267 ckinode(dp, ADDR);
1268 zapino(dp);
f3c028b7 1269 setstate(USTATE);
6e884967
KM
1270 inodirty();
1271 inosumbad++;
1272 }
1273}
1274
1275setup(dev)
8ebf61ca 1276 char *dev;
6e884967
KM
1277{
1278 dev_t rootdev;
4d308541 1279 struct stat statb;
6e884967 1280 int super = bflag ? bflag : SBLOCK;
bf541624
KM
1281 int i, j, size;
1282 int c, d, cgd;
6e884967
KM
1283
1284 bflag = 0;
1285 if (stat("/", &statb) < 0)
1286 errexit("Can't stat root\n");
1287 rootdev = statb.st_dev;
1288 if (stat(dev, &statb) < 0) {
1289 error("Can't stat %s\n", dev);
1290 return (0);
1291 }
1292 rawflg = 0;
1293 if ((statb.st_mode & S_IFMT) == S_IFBLK)
1294 ;
1295 else if ((statb.st_mode & S_IFMT) == S_IFCHR)
1296 rawflg++;
1297 else {
1298 if (reply("file is not a block or character device; OK") == 0)
1299 return (0);
1300 }
1301 if (rootdev == statb.st_rdev)
1302 hotroot++;
1303 if ((dfile.rfdes = open(dev, 0)) < 0) {
1304 error("Can't open %s\n", dev);
1305 return (0);
1306 }
1307 if (preen == 0)
1308 printf("** %s", dev);
1309 if (nflag || (dfile.wfdes = open(dev, 1)) < 0) {
1310 dfile.wfdes = -1;
1311 if (preen)
1312 pfatal("NO WRITE ACCESS");
1313 printf(" (NO WRITE)");
1314 }
1315 if (preen == 0)
1316 printf("\n");
184d432f 1317 fixcg = 0; inosumbad = 0; offsumbad = 0; frsumbad = 0; sbsumbad = 0;
6e884967
KM
1318 dfile.mod = 0;
1319 n_files = n_blks = n_ffree = n_bfree = 0;
1320 muldup = enddup = &duplist[0];
1321 badlnp = &badlncnt[0];
1322 lfdir = 0;
1323 rplyflag = 0;
1324 initbarea(&sblk);
1325 initbarea(&fileblk);
1326 initbarea(&inoblk);
1327 initbarea(&cgblk);
184d432f
KM
1328 /*
1329 * Read in the super block and its summary info.
1330 */
c312eebd 1331 if (bread(&dfile, &sblock, super, SBSIZE) == 0)
6e884967 1332 return (0);
f3c028b7 1333 sblk.b_bno = super;
c312eebd 1334 sblk.b_size = SBSIZE;
aca50d72
KM
1335 /*
1336 * run a few consistency checks of the super block
1337 */
6e884967
KM
1338 if (sblock.fs_magic != FS_MAGIC)
1339 { badsb("MAGIC NUMBER WRONG"); return (0); }
1340 if (sblock.fs_ncg < 1)
1341 { badsb("NCG OUT OF RANGE"); return (0); }
1342 if (sblock.fs_cpg < 1 || sblock.fs_cpg > MAXCPG)
1343 { badsb("CPG OUT OF RANGE"); return (0); }
1344 if (sblock.fs_nsect < 1)
1345 { badsb("NSECT < 1"); return (0); }
1346 if (sblock.fs_ntrak < 1)
1347 { badsb("NTRAK < 1"); return (0); }
aca50d72
KM
1348 if (sblock.fs_spc != sblock.fs_nsect * sblock.fs_ntrak)
1349 { badsb("SPC DOES NOT JIVE w/NTRAK*NSECT"); return (0); }
1350 if (sblock.fs_ipg % INOPB(&sblock))
1351 { badsb("INODES NOT MULTIPLE OF A BLOCK"); return (0); }
6994bf5d 1352 if (cgdmin(&sblock, 0) >= sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
6e884967 1353 { badsb("IMPLIES MORE INODE THAN DATA BLOCKS"); return (0); }
aca50d72
KM
1354 if (sblock.fs_ncg * sblock.fs_cpg < sblock.fs_ncyl ||
1355 (sblock.fs_ncg - 1) * sblock.fs_cpg >= sblock.fs_ncyl)
6e884967 1356 { badsb("NCYL DOES NOT JIVE WITH NCG*CPG"); return (0); }
b6407c9d 1357 if (sblock.fs_fpg != sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock))
6e884967 1358 { badsb("FPG DOES NOT JIVE WITH CPG & SPC"); return (0); }
aca50d72
KM
1359 if (sblock.fs_size * NSPF(&sblock) <=
1360 (sblock.fs_ncyl - 1) * sblock.fs_spc)
6e884967 1361 { badsb("SIZE PREPOSTEROUSLY SMALL"); return (0); }
aca50d72 1362 if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc)
6e884967
KM
1363 { badsb("SIZE PREPOSTEROUSLY LARGE"); return (0); }
1364 /* rest we COULD repair... */
3352e84a
KM
1365 if (sblock.fs_cgsize != fragroundup(&sblock,
1366 sizeof(struct cg) + howmany(sblock.fs_fpg, NBBY)))
6e884967 1367 { badsb("CGSIZE INCORRECT"); return (0); }
bf541624
KM
1368 if (sblock.fs_cssize !=
1369 fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)))
6e884967
KM
1370 { badsb("CSSIZE INCORRECT"); return (0); }
1371 fmax = sblock.fs_size;
1372 imax = sblock.fs_ncg * sblock.fs_ipg;
bf541624
KM
1373 n_bad = cgsblock(&sblock, 0); /* boot block plus dedicated sblock */
1374 /*
1375 * read in the summary info.
1376 */
1377 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
1378 size = sblock.fs_cssize - i < sblock.fs_bsize ?
1379 sblock.fs_cssize - i : sblock.fs_bsize;
1380 sblock.fs_csp[j] = (struct csum *)calloc(1, size);
1381 bread(&dfile, (char *)sblock.fs_csp[j],
1382 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
1383 size);
1384 }
aca50d72 1385 /*
bf541624 1386 * allocate and initialize the necessary maps
aca50d72 1387 */
6e884967 1388 bmapsz = roundup(howmany(fmax, NBBY), sizeof(short));
79f5f76a 1389 blockmap = (char *)calloc(bmapsz, sizeof (char));
f3385032
KM
1390 if (blockmap == NULL) {
1391 printf("cannot alloc %d bytes for blockmap\n", bmapsz);
1392 exit(1);
1393 }
6e884967 1394 freemap = (char *)calloc(bmapsz, sizeof (char));
f3385032
KM
1395 if (freemap == NULL) {
1396 printf("cannot alloc %d bytes for freemap\n", bmapsz);
1397 exit(1);
1398 }
6e884967 1399 statemap = (char *)calloc(imax+1, sizeof(char));
f3385032
KM
1400 if (statemap == NULL) {
1401 printf("cannot alloc %d bytes for statemap\n", imax + 1);
1402 exit(1);
1403 }
6e884967 1404 lncntp = (short *)calloc(imax+1, sizeof(short));
f3385032
KM
1405 if (lncntp == NULL) {
1406 printf("cannot alloc %d bytes for lncntp\n",
1407 (imax + 1) * sizeof(short));
1408 exit(1);
1409 }
bf541624
KM
1410 for (c = 0; c < sblock.fs_ncg; c++) {
1411 cgd = cgdmin(&sblock, c);
1412 if (c == 0) {
1413 d = cgbase(&sblock, c);
1414 cgd += howmany(sblock.fs_cssize, sblock.fs_fsize);
1415 } else
1416 d = cgsblock(&sblock, c);
1417 for (; d < cgd; d++)
1418 setbmap(d);
1419 }
6e884967 1420
f3c028b7 1421 startinum = imax + 1;
6e884967
KM
1422 return (1);
1423
1424badsb:
1425 ckfini();
1426 return (0);
1427}
1428
1429badsb(s)
1430 char *s;
1431{
1432
1433 if (preen)
1434 printf("%s: ", devname);
1435 printf("BAD SUPER BLOCK: %s\n", s);
1436 pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
1437 pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
1438}
1439
1440DINODE *
1441ginode()
1442{
1443 daddr_t iblk;
1444
f3385032
KM
1445 if (inum < ROOTINO || inum > imax) {
1446 if (debug && (inum < 0 || inum > imax))
1447 printf("inum out of range (%d)\n", inum);
6e884967 1448 return (NULL);
f3385032 1449 }
b6407c9d 1450 if (inum < startinum || inum >= startinum + INOPB(&sblock)) {
6994bf5d 1451 iblk = itod(&sblock, inum);
b6407c9d 1452 if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
6e884967
KM
1453 return (NULL);
1454 }
b6407c9d 1455 startinum = (inum / INOPB(&sblock)) * INOPB(&sblock);
6e884967 1456 }
b6407c9d 1457 return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]);
6e884967
KM
1458}
1459
1460ftypeok(dp)
1461 DINODE *dp;
1462{
1463 switch (dp->di_mode & IFMT) {
1464
1465 case IFDIR:
1466 case IFREG:
1467 case IFBLK:
1468 case IFCHR:
ea47352d 1469 case IFLNK:
6e884967
KM
1470 return (1);
1471
1472 default:
1473 return (0);
1474 }
1475}
1476
1477reply(s)
1478 char *s;
1479{
1480 char line[80];
1481
1482 if (preen)
1483 pfatal("INTERNAL ERROR: GOT TO reply()");
1484 rplyflag = 1;
1485 printf("\n%s? ", s);
1486 if (nflag || dfile.wfdes < 0) {
1487 printf(" no\n\n");
1488 return (0);
1489 }
1490 if (yflag) {
1491 printf(" yes\n\n");
1492 return (1);
1493 }
1494 if (getline(stdin, line, sizeof(line)) == EOF)
1495 errexit("\n");
1496 printf("\n");
1497 if (line[0] == 'y' || line[0] == 'Y')
1498 return (1);
1499 else
1500 return (0);
1501}
1502
1503getline(fp, loc, maxlen)
1504 FILE *fp;
1505 char *loc;
1506{
1507 register n;
1508 register char *p, *lastloc;
1509
1510 p = loc;
1511 lastloc = &p[maxlen-1];
1512 while ((n = getc(fp)) != '\n') {
1513 if (n == EOF)
1514 return (EOF);
1515 if (!isspace(n) && p < lastloc)
1516 *p++ = n;
1517 }
1518 *p = 0;
1519 return (p - loc);
1520}
1521
1522BUFAREA *
1523getblk(bp, blk, size)
1524 daddr_t blk;
1525 register BUFAREA *bp;
1526 int size;
1527{
1528 register struct filecntl *fcp;
b6407c9d 1529 daddr_t dblk;
6e884967
KM
1530
1531 fcp = &dfile;
b6407c9d
KM
1532 dblk = fsbtodb(&sblock, blk);
1533 if (bp->b_bno == dblk)
6e884967
KM
1534 return (bp);
1535 flush(fcp, bp);
b6407c9d
KM
1536 if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
1537 bp->b_bno = dblk;
6e884967
KM
1538 bp->b_size = size;
1539 return (bp);
1540 }
1541 bp->b_bno = (daddr_t)-1;
1542 return (NULL);
1543}
1544
1545flush(fcp, bp)
1546 struct filecntl *fcp;
1547 register BUFAREA *bp;
1548{
1549
1550 if (bp->b_dirty)
1551 bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size);
1552 bp->b_dirty = 0;
1553}
1554
1555rwerr(s, blk)
1556 char *s;
1557 daddr_t blk;
1558{
1559
1560 if (preen == 0)
1561 printf("\n");
1562 pfatal("CANNOT %s: BLK %ld", s, blk);
1563 if (reply("CONTINUE") == 0)
1564 errexit("Program terminated\n");
1565}
1566
1567ckfini()
1568{
1569
1570 flush(&dfile, &fileblk);
1571 flush(&dfile, &sblk);
f3c028b7
KM
1572 if (sblk.b_bno != SBLOCK) {
1573 sblk.b_bno = SBLOCK;
1574 sbdirty();
1575 flush(&dfile, &sblk);
1576 }
6e884967
KM
1577 flush(&dfile, &inoblk);
1578 close(dfile.rfdes);
1579 close(dfile.wfdes);
1580}
1581
1582pinode()
1583{
1584 register DINODE *dp;
1585 register char *p;
24a31719 1586 char uidbuf[BUFSIZ];
6e884967
KM
1587 char *ctime();
1588
1589 printf(" I=%u ", inum);
1590 if ((dp = ginode()) == NULL)
1591 return;
1592 printf(" OWNER=");
1593 if (getpw((int)dp->di_uid, uidbuf) == 0) {
1594 for (p = uidbuf; *p != ':'; p++);
1595 *p = 0;
1596 printf("%s ", uidbuf);
1597 }
1598 else {
1599 printf("%d ", dp->di_uid);
1600 }
1601 printf("MODE=%o\n", dp->di_mode);
1602 if (preen)
1603 printf("%s: ", devname);
1604 printf("SIZE=%ld ", dp->di_size);
1605 p = ctime(&dp->di_mtime);
1606 printf("MTIME=%12.12s %4.4s ", p+4, p+20);
1607}
1608
1609copy(fp, tp, size)
1610 register char *tp, *fp;
1611 unsigned size;
1612{
1613
1614 while (size--)
1615 *tp++ = *fp++;
1616}
1617
1618makecg()
1619{
f3c028b7 1620 int c, blk;
bf541624 1621 daddr_t dbase, d, dlower, dupper, dmax;
6e884967
KM
1622 long i, j, s;
1623 register struct csum *cs;
f3c028b7 1624 register DINODE *dp;
6e884967 1625
0947395d
KM
1626 sblock.fs_cstotal.cs_nbfree = 0;
1627 sblock.fs_cstotal.cs_nffree = 0;
1628 sblock.fs_cstotal.cs_nifree = 0;
1629 sblock.fs_cstotal.cs_ndir = 0;
6e884967 1630 for (c = 0; c < sblock.fs_ncg; c++) {
6994bf5d 1631 dbase = cgbase(&sblock, c);
6e884967 1632 dmax = dbase + sblock.fs_fpg;
8f99f49c 1633 if (dmax > sblock.fs_size) {
bf4c734c 1634 for ( ; dmax >= sblock.fs_size; dmax--)
2e9860b5 1635 clrbit(cgrp.cg_free, dmax - dbase);
8f99f49c
KM
1636 dmax++;
1637 }
bf541624
KM
1638 dlower = cgsblock(&sblock, c) - dbase;
1639 dupper = cgdmin(&sblock, c) - dbase;
b6407c9d 1640 cs = &sblock.fs_cs(&sblock, c);
6e884967
KM
1641 cgrp.cg_time = time(0);
1642 cgrp.cg_magic = CG_MAGIC;
1643 cgrp.cg_cgx = c;
1644 cgrp.cg_ncyl = sblock.fs_cpg;
1645 cgrp.cg_niblk = sblock.fs_ipg;
1646 cgrp.cg_ndblk = dmax - dbase;
0947395d
KM
1647 cgrp.cg_cs.cs_ndir = 0;
1648 cgrp.cg_cs.cs_nffree = 0;
1649 cgrp.cg_cs.cs_nbfree = 0;
1650 cgrp.cg_cs.cs_nifree = 0;
bf541624
KM
1651 cgrp.cg_rotor = 0;
1652 cgrp.cg_frotor = 0;
92ea6158 1653 cgrp.cg_irotor = 0;
b6407c9d 1654 for (i = 0; i < sblock.fs_frag; i++)
f3c028b7 1655 cgrp.cg_frsum[i] = 0;
6e884967 1656 inum = sblock.fs_ipg * c;
f3c028b7 1657 for (i = 0; i < sblock.fs_ipg; inum++, i++) {
bf4c734c
KM
1658 cgrp.cg_cs.cs_nifree++;
1659 clrbit(cgrp.cg_iused, i);
f3c028b7
KM
1660 dp = ginode();
1661 if (dp == NULL)
1662 continue;
1663 if (ALLOC) {
24a31719 1664 if (DIRCT)
0947395d 1665 cgrp.cg_cs.cs_ndir++;
bf4c734c 1666 cgrp.cg_cs.cs_nifree--;
f3c028b7
KM
1667 setbit(cgrp.cg_iused, i);
1668 continue;
1669 }
6e884967
KM
1670 }
1671 while (i < MAXIPG) {
1672 clrbit(cgrp.cg_iused, i);
1673 i++;
1674 }
bf4c734c
KM
1675 if (c == 0)
1676 for (i = 0; i < ROOTINO; i++) {
1677 setbit(cgrp.cg_iused, i);
1678 cgrp.cg_cs.cs_nifree--;
1679 }
43f6367c
KM
1680 for (s = 0; s < MAXCPG; s++) {
1681 cgrp.cg_btot[s] = 0;
6e884967
KM
1682 for (i = 0; i < NRPOS; i++)
1683 cgrp.cg_b[s][i] = 0;
43f6367c 1684 }
6e884967 1685 if (c == 0) {
bf541624 1686 dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
6e884967 1687 }
bf541624 1688 for (d = dlower; d < dupper; d++)
6e884967 1689 clrbit(cgrp.cg_free, d);
bf541624
KM
1690 for (d = 0; (d + sblock.fs_frag) <= dmax - dbase;
1691 d += sblock.fs_frag) {
6e884967 1692 j = 0;
b6407c9d 1693 for (i = 0; i < sblock.fs_frag; i++) {
bf541624
KM
1694 if (!getbmap(dbase + d + i)) {
1695 setbit(cgrp.cg_free, d + i);
6e884967
KM
1696 j++;
1697 } else
1698 clrbit(cgrp.cg_free, d+i);
1699 }
b6407c9d 1700 if (j == sblock.fs_frag) {
0947395d 1701 cgrp.cg_cs.cs_nbfree++;
43f6367c 1702 cgrp.cg_btot[cbtocylno(&sblock, d)]++;
aca50d72
KM
1703 cgrp.cg_b[cbtocylno(&sblock, d)]
1704 [cbtorpos(&sblock, d)]++;
f3c028b7 1705 } else if (j > 0) {
0947395d 1706 cgrp.cg_cs.cs_nffree += j;
bf541624 1707 blk = blkmap(&sblock, cgrp.cg_free, d);
b6407c9d 1708 fragacct(&sblock, blk, cgrp.cg_frsum, 1);
f3c028b7 1709 }
6e884967 1710 }
f3c028b7 1711 for (j = d; d < dmax - dbase; d++) {
bf541624 1712 if (!getbmap(dbase + d)) {
6e884967 1713 setbit(cgrp.cg_free, d);
0947395d 1714 cgrp.cg_cs.cs_nffree++;
6e884967
KM
1715 } else
1716 clrbit(cgrp.cg_free, d);
1717 }
f3c028b7 1718 if (j != d) {
bf541624 1719 blk = blkmap(&sblock, cgrp.cg_free, j);
b6407c9d 1720 fragacct(&sblock, blk, cgrp.cg_frsum, 1);
f3c028b7 1721 }
b6407c9d 1722 for (; d < MAXBPG(&sblock); d++)
6e884967 1723 clrbit(cgrp.cg_free, d);
0947395d
KM
1724 sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree;
1725 sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree;
1726 sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
1727 sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
1728 *cs = cgrp.cg_cs;
6994bf5d 1729 bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)),
3352e84a 1730 sblock.fs_cgsize);
6e884967 1731 }
bf541624
KM
1732 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
1733 bwrite(&dfile, (char *)sblock.fs_csp[j],
1734 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
1735 sblock.fs_cssize - i < sblock.fs_bsize ?
1736 sblock.fs_cssize - i : sblock.fs_bsize);
c2a050cf 1737 }
6e884967
KM
1738 sblock.fs_ronly = 0;
1739 sblock.fs_fmod = 0;
1740 sbdirty();
1741}
1742
f3c028b7
KM
1743/*
1744 * update the frsum fields to reflect addition or deletion
1745 * of some frags
1746 */
b6407c9d
KM
1747fragacct(fs, fragmap, fraglist, cnt)
1748 struct fs *fs;
1b940b13 1749 int fragmap;
0947395d 1750 long fraglist[];
f3c028b7
KM
1751 int cnt;
1752{
1753 int inblk;
1754 register int field, subfield;
1755 register int siz, pos;
1756
b6407c9d 1757 inblk = (int)(fragtbl[fs->fs_frag][fragmap] << 1);
f3c028b7 1758 fragmap <<= 1;
b6407c9d 1759 for (siz = 1; siz < fs->fs_frag; siz++) {
156b8f82 1760 if ((inblk & (1 << (siz + (fs->fs_frag % NBBY)))) == 0)
f3c028b7
KM
1761 continue;
1762 field = around[siz];
1763 subfield = inside[siz];
b6407c9d 1764 for (pos = siz; pos <= fs->fs_frag; pos++) {
f3c028b7
KM
1765 if ((fragmap & field) == subfield) {
1766 fraglist[siz] += cnt;
1767 pos += siz;
1768 field <<= siz;
1769 subfield <<= siz;
1770 }
1771 field <<= 1;
1772 subfield <<= 1;
1773 }
1774 }
1775}
1776
6e884967
KM
1777findino(dirp)
1778 register DIRECT *dirp;
1779{
6e884967
KM
1780 if (dirp->d_ino == 0)
1781 return (KEEPON);
24a31719
KM
1782 if (!strcmp(dirp->d_name, srchname)) {
1783 if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
1784 parentdir = dirp->d_ino;
1785 return (STOP);
6e884967
KM
1786 }
1787 return (KEEPON);
1788}
1789
1790mkentry(dirp)
1791 register DIRECT *dirp;
1792{
1793 register ino_t in;
1794 register char *p;
754cadb5
KM
1795 DIRECT newent;
1796 int newlen, oldlen;
6e884967 1797
754cadb5
KM
1798 newent.d_namlen = 11;
1799 newlen = DIRSIZ(&newent);
1800 if (dirp->d_ino != 0)
1801 oldlen = DIRSIZ(dirp);
1802 else
1803 oldlen = 0;
1804 if (dirp->d_reclen - oldlen < newlen)
6e884967 1805 return (KEEPON);
754cadb5
KM
1806 newent.d_reclen = dirp->d_reclen - oldlen;
1807 dirp->d_reclen = oldlen;
1808 dirp = (struct direct *)(((char *)dirp) + oldlen);
6e884967 1809 dirp->d_ino = orphan;
754cadb5
KM
1810 dirp->d_reclen = newent.d_reclen;
1811 p = &dirp->d_name[2];
1812 for (in = imax; in > 0; in /= 10)
1813 p++;
6e884967 1814 *--p = 0;
754cadb5
KM
1815 dirp->d_namlen = p - dirp->d_name;
1816 in = orphan;
6e884967
KM
1817 while (p > dirp->d_name) {
1818 *--p = (in % 10) + '0';
1819 in /= 10;
1820 }
1821 *p = '#';
1822 return (ALTERD|STOP);
1823}
1824
1825chgdd(dirp)
1826 register DIRECT *dirp;
1827{
1828 if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
1829 dirp->d_name[2] == 0) {
1830 dirp->d_ino = lfdir;
1831 return (ALTERD|STOP);
1832 }
1833 return (KEEPON);
1834}
1835
1836linkup()
1837{
1838 register DINODE *dp;
1839 register lostdir;
1840 register ino_t pdir;
1841
1842 if ((dp = ginode()) == NULL)
1843 return (0);
24a31719 1844 lostdir = DIRCT;
6e884967
KM
1845 pdir = parentdir;
1846 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
1847 pinode();
1848 if (preen && dp->di_size == 0)
1849 return (0);
1850 if (preen)
1851 printf(" (RECONNECTED)\n");
1852 else
1853 if (reply("RECONNECT") == 0)
1854 return (0);
1855 orphan = inum;
1856 if (lfdir == 0) {
1857 inum = ROOTINO;
1858 if ((dp = ginode()) == NULL) {
1859 inum = orphan;
1860 return (0);
1861 }
1862 pfunc = findino;
1863 srchname = lfname;
1864 filsize = dp->di_size;
1865 parentdir = 0;
1866 ckinode(dp, DATA);
1867 inum = orphan;
1868 if ((lfdir = parentdir) == 0) {
1869 pfatal("SORRY. NO lost+found DIRECTORY");
1870 printf("\n\n");
1871 return (0);
1872 }
1873 }
1874 inum = lfdir;
24a31719 1875 if ((dp = ginode()) == NULL || !DIRCT || getstate() != FSTATE) {
6e884967
KM
1876 inum = orphan;
1877 pfatal("SORRY. NO lost+found DIRECTORY");
1878 printf("\n\n");
1879 return (0);
1880 }
3352e84a
KM
1881 if (fragoff(&sblock, dp->di_size)) {
1882 dp->di_size = fragroundup(&sblock, dp->di_size);
6e884967
KM
1883 inodirty();
1884 }
1885 filsize = dp->di_size;
1886 inum = orphan;
1887 pfunc = mkentry;
1888 if ((ckinode(dp, DATA) & ALTERD) == 0) {
1889 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
1890 printf("\n\n");
1891 return (0);
1892 }
1893 declncnt();
1894 if (lostdir) {
1895 pfunc = chgdd;
1896 dp = ginode();
1897 filsize = dp->di_size;
1898 ckinode(dp, DATA);
1899 inum = lfdir;
1900 if ((dp = ginode()) != NULL) {
1901 dp->di_nlink++;
1902 inodirty();
1903 setlncnt(getlncnt()+1);
1904 }
1905 inum = orphan;
1906 pwarn("DIR I=%u CONNECTED. ", orphan);
1907 printf("PARENT WAS I=%u\n", pdir);
1908 if (preen == 0)
1909 printf("\n");
1910 }
1911 return (1);
1912}
1913
1914bread(fcp, buf, blk, size)
1915 daddr_t blk;
1916 register struct filecntl *fcp;
1917 register size;
1918 char *buf;
1919{
b6407c9d 1920 if (lseek(fcp->rfdes, blk * DEV_BSIZE, 0) < 0)
6e884967
KM
1921 rwerr("SEEK", blk);
1922 else if (read(fcp->rfdes, buf, size) == size)
1923 return (1);
1924 rwerr("READ", blk);
1925 return (0);
1926}
1927
1928bwrite(fcp, buf, blk, size)
1929 daddr_t blk;
1930 register struct filecntl *fcp;
1931 register size;
1932 char *buf;
1933{
1934
1935 if (fcp->wfdes < 0)
1936 return (0);
b6407c9d 1937 if (lseek(fcp->wfdes, blk * DEV_BSIZE, 0) < 0)
6e884967
KM
1938 rwerr("SEEK", blk);
1939 else if (write(fcp->wfdes, buf, size) == size) {
1940 fcp->mod = 1;
1941 return (1);
1942 }
1943 rwerr("WRITE", blk);
1944 return (0);
1945}
1946
1947catch()
1948{
1949
1950 ckfini();
1951 exit(12);
1952}
b6407c9d
KM
1953
1954/*
1955 * block operations
1956 */
1957
1958isblock(fs, cp, h)
1959 struct fs *fs;
1960 unsigned char *cp;
1961 int h;
1962{
1963 unsigned char mask;
1964
1965 switch (fs->fs_frag) {
1966 case 8:
1967 return (cp[h] == 0xff);
1968 case 4:
1969 mask = 0x0f << ((h & 0x1) << 2);
1970 return ((cp[h >> 1] & mask) == mask);
1971 case 2:
1972 mask = 0x03 << ((h & 0x3) << 1);
1973 return ((cp[h >> 2] & mask) == mask);
1974 case 1:
1975 mask = 0x01 << (h & 0x7);
1976 return ((cp[h >> 3] & mask) == mask);
1977 default:
6994bf5d
KM
1978 error("isblock bad fs_frag %d\n", fs->fs_frag);
1979 return (0);
b6407c9d
KM
1980 }
1981}
4d308541
KM
1982
1983/* tables.c 4.1 82/03/25 */
1984
1985/* merged into kernel: tables.c 2.1 3/25/82 */
1986
1987/* last monet version: partab.c 4.2 81/03/08 */
1988
1989/*
1990 * bit patterns for identifying fragments in the block map
1991 * used as ((map & around) == inside)
1992 */
1993int around[9] = {
1994 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
1995};
1996int inside[9] = {
1997 0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
1998};
1999
2000/*
2001 * given a block map bit pattern, the frag tables tell whether a
2002 * particular size fragment is available.
2003 *
2004 * used as:
2005 * if ((1 << (size - 1)) & fragtbl[fs->fs_frag][map] {
2006 * at least one fragment of the indicated size is available
2007 * }
2008 *
2009 * These tables are used by the scanc instruction on the VAX to
2010 * quickly find an appropriate fragment.
2011 */
2012
2013unsigned char fragtbl124[256] = {
2014 0x00, 0x16, 0x16, 0x2a, 0x16, 0x16, 0x26, 0x4e,
2015 0x16, 0x16, 0x16, 0x3e, 0x2a, 0x3e, 0x4e, 0x8a,
2016 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
2017 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
2018 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
2019 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
2020 0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
2021 0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
2022 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
2023 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
2024 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
2025 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
2026 0x26, 0x36, 0x36, 0x2e, 0x36, 0x36, 0x26, 0x6e,
2027 0x36, 0x36, 0x36, 0x3e, 0x2e, 0x3e, 0x6e, 0xae,
2028 0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
2029 0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
2030 0x16, 0x16, 0x16, 0x3e, 0x16, 0x16, 0x36, 0x5e,
2031 0x16, 0x16, 0x16, 0x3e, 0x3e, 0x3e, 0x5e, 0x9e,
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 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
2037 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
2038 0x2a, 0x3e, 0x3e, 0x2a, 0x3e, 0x3e, 0x2e, 0x6e,
2039 0x3e, 0x3e, 0x3e, 0x3e, 0x2a, 0x3e, 0x6e, 0xaa,
2040 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e,
2041 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x7e, 0xbe,
2042 0x4e, 0x5e, 0x5e, 0x6e, 0x5e, 0x5e, 0x6e, 0x4e,
2043 0x5e, 0x5e, 0x5e, 0x7e, 0x6e, 0x7e, 0x4e, 0xce,
2044 0x8a, 0x9e, 0x9e, 0xaa, 0x9e, 0x9e, 0xae, 0xce,
2045 0x9e, 0x9e, 0x9e, 0xbe, 0xaa, 0xbe, 0xce, 0x8a,
2046};
2047
2048unsigned char fragtbl8[256] = {
2049 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04,
2050 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
2051 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
2052 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
2053 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
2054 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
2055 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
2056 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
2057 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
2058 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
2059 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
2060 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
2061 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
2062 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
2063 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
2064 0x08, 0x09, 0x09, 0x0a, 0x10, 0x11, 0x20, 0x40,
2065 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
2066 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
2067 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
2068 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
2069 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05,
2070 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
2071 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
2072 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
2073 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06,
2074 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0a,
2075 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
2076 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0a, 0x12,
2077 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04,
2078 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0c,
2079 0x08, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x0a, 0x0c,
2080 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
2081};
2082
2083/*
2084 * the actual fragtbl array
2085 */
2086unsigned char *fragtbl[MAXFRAG + 1] = {
2087 0, fragtbl124, fragtbl124, 0, fragtbl124, 0, 0, 0, fragtbl8,
2088};