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