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