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