protocol change; byte swap those fields which need it; also add
[unix-history] / usr / src / sbin / fsck / main.c
CommitLineData
5e01ca34 1char version[] = "@(#)main.c 2.23 (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);
5e01ca34
KM
635 filsize *= btodb(sblock.fs_fsize);
636 if (dp->di_blocks != filsize) {
637 pwarn("INCORRECT BLOCK COUNT I=%u (%ld should be %ld)",
638 inum, dp->di_blocks, filsize);
639 if (preen)
640 printf(" (CORRECTED)\n");
641 else if (reply("CORRECT") == 0)
642 continue;
643 dp->di_blocks = filsize;
644 inodirty();
645 }
6bccc723
KM
646 continue;
647 unknown:
af5ba2f8
KM
648 if (!SOCK)
649 pfatal("UNKNOWN FILE TYPE I=%u", inum);
650 if ((preen && SOCK) || reply("CLEAR") == 1) {
6bccc723
KM
651 zapino(dp);
652 inodirty();
653 inosumbad++;
654 }
6e884967 655 } else {
6e884967 656 if (isset(cgrp.cg_iused, i)) {
6994bf5d
KM
657 if (debug)
658 printf("%d bad, marked used\n",
659 inum);
6e884967 660 inosumbad++;
f3c028b7 661 n--;
6e884967 662 }
6bccc723
KM
663 partial = 0;
664 for (j = 0; j < NDADDR; j++)
665 if (dp->di_db[j] != 0)
666 partial++;
667 for (j = 0; j < NIADDR; j++)
668 if (dp->di_ib[j] != 0)
669 partial++;
670 if (partial || dp->di_mode != 0 ||
671 dp->di_size != 0) {
6e884967
KM
672 pfatal("PARTIALLY ALLOCATED INODE I=%u", inum);
673 if (reply("CLEAR") == 1) {
674 zapino(dp);
675 inodirty();
676 inosumbad++;
677 }
678 }
679 }
680 }
0947395d 681 if (n != cgrp.cg_cs.cs_nifree) {
6994bf5d 682 if (debug)
bf4c734c 683 printf("cg[%d].cg_cs.cs_nifree is %d; calc %d\n",
6994bf5d 684 c, cgrp.cg_cs.cs_nifree, n);
6e884967
KM
685 inosumbad++;
686 }
184d432f
KM
687 if (cgrp.cg_cs.cs_nbfree != sblock.fs_cs(&sblock, c).cs_nbfree
688 || cgrp.cg_cs.cs_nffree != sblock.fs_cs(&sblock, c).cs_nffree
689 || cgrp.cg_cs.cs_nifree != sblock.fs_cs(&sblock, c).cs_nifree
690 || cgrp.cg_cs.cs_ndir != sblock.fs_cs(&sblock, c).cs_ndir)
691 sbsumbad++;
6e884967 692 }
d2c95d76
BJ
693}
694
695pass1check(blk, size)
696 daddr_t blk;
697 int size;
698{
699 register daddr_t *dlp;
700 int res = KEEPON;
f5971be7 701 int anyout;
d2c95d76 702
f5971be7 703 anyout = outrange(blk, size);
d2c95d76 704 for (; size > 0; blk++, size--) {
f5971be7 705 if (anyout && outrange(blk, 1)) {
d2c95d76
BJ
706 blkerr("BAD", blk);
707 if (++badblk >= MAXBAD) {
708 pwarn("EXCESSIVE BAD BLKS I=%u", inum);
709 if (preen)
710 printf(" (SKIPPING)\n");
711 else if (reply("CONTINUE") == 0)
712 errexit("");
713 return (STOP);
714 }
715 res = SKIP;
716 } else if (getbmap(blk)) {
717 blkerr("DUP", blk);
718 if (++dupblk >= MAXDUP) {
719 pwarn("EXCESSIVE DUP BLKS I=%u", inum);
720 if (preen)
721 printf(" (SKIPPING)\n");
722 else if (reply("CONTINUE") == 0)
723 errexit("");
724 return (STOP);
725 }
726 if (enddup >= &duplist[DUPTBLSIZE]) {
727 pfatal("DUP TABLE OVERFLOW.");
728 if (reply("CONTINUE") == 0)
729 errexit("");
730 return (STOP);
731 }
732 for (dlp = duplist; dlp < muldup; dlp++)
733 if (*dlp == blk) {
734 *enddup++ = blk;
735 break;
736 }
737 if (dlp >= muldup) {
738 *enddup++ = *muldup;
739 *muldup++ = blk;
f3c028b7 740 }
d2c95d76
BJ
741 } else {
742 n_blks++;
743 setbmap(blk);
744 }
745 filsize++;
746 }
747 return (res);
748}
749
750pass1b()
751{
752 register int c, i;
753 register DINODE *dp;
754
755 pfunc = pass1bcheck;
756 inum = 0;
757 for (c = 0; c < sblock.fs_ncg; c++) {
758 for (i = 0; i < sblock.fs_ipg; i++, inum++) {
759 dp = ginode();
760 if (dp == NULL)
761 continue;
f5262822 762 if (statemap[inum] != USTATE &&
d2c95d76
BJ
763 (ckinode(dp, ADDR) & STOP))
764 goto out1b;
6e884967
KM
765 }
766 }
767out1b:
f3c028b7 768 flush(&dfile, &inoblk);
d2c95d76
BJ
769}
770
771pass1bcheck(blk, size)
772 daddr_t blk;
773 int size;
774{
775 register daddr_t *dlp;
776 int res = KEEPON;
777
778 for (; size > 0; blk++, size--) {
f5971be7 779 if (outrange(blk, 1))
d2c95d76
BJ
780 res = SKIP;
781 for (dlp = duplist; dlp < muldup; dlp++)
782 if (*dlp == blk) {
783 blkerr("DUP", blk);
784 *dlp = *--muldup;
785 *muldup = blk;
786 if (muldup == duplist)
787 return (STOP);
788 }
789 }
790 return (res);
791}
792
793pass2()
794{
795 register DINODE *dp;
796
6e884967
KM
797 inum = ROOTINO;
798 thisname = pathp = pathname;
d2c95d76 799 pfunc = pass2check;
f5262822 800 switch (statemap[inum]) {
6e884967
KM
801
802 case USTATE:
803 errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
804
805 case FSTATE:
806 pfatal("ROOT INODE NOT DIRECTORY");
807 if (reply("FIX") == 0 || (dp = ginode()) == NULL)
808 errexit("");
809 dp->di_mode &= ~IFMT;
810 dp->di_mode |= IFDIR;
811 inodirty();
812 inosumbad++;
f5262822 813 statemap[inum] = DSTATE;
6e884967
KM
814 /* fall into ... */
815
816 case DSTATE:
817 descend();
818 break;
819
820 case CLEAR:
821 pfatal("DUPS/BAD IN ROOT INODE");
822 printf("\n");
823 if (reply("CONTINUE") == 0)
824 errexit("");
f5262822 825 statemap[inum] = DSTATE;
6e884967
KM
826 descend();
827 }
d2c95d76
BJ
828}
829
830pass2check(dirp)
831 register DIRECT *dirp;
832{
833 register char *p;
834 register n;
835 DINODE *dp;
836
837 if ((inum = dirp->d_ino) == 0)
838 return (KEEPON);
839 thisname = pathp;
aac37e2e
KM
840 if (pathp + dirp->d_namlen >= endpathname) {
841 *pathp = '\0';
842 errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name);
843 }
d2c95d76
BJ
844 for (p = dirp->d_name; p < &dirp->d_name[MAXNAMLEN]; )
845 if ((*pathp++ = *p++) == 0) {
846 --pathp;
847 break;
848 }
849 *pathp = 0;
850 n = 0;
851 if (inum > imax || inum <= 0)
852 n = direrr("I OUT OF RANGE");
853 else {
854again:
f5262822 855 switch (statemap[inum]) {
d2c95d76
BJ
856 case USTATE:
857 n = direrr("UNALLOCATED");
858 break;
859
860 case CLEAR:
861 if ((n = direrr("DUP/BAD")) == 1)
862 break;
863 if ((dp = ginode()) == NULL)
864 break;
f5262822 865 statemap[inum] = DIRCT ? DSTATE : FSTATE;
d2c95d76
BJ
866 goto again;
867
868 case FSTATE:
f5262822 869 lncntp[inum]--;
d2c95d76
BJ
870 break;
871
872 case DSTATE:
f5262822 873 lncntp[inum]--;
d2c95d76
BJ
874 descend();
875 break;
876 }
877 }
878 pathp = thisname;
879 if (n == 0)
880 return (KEEPON);
881 dirp->d_ino = 0;
882 return (KEEPON|ALTERD);
883}
884
885pass3()
886{
887 ino_t savino;
888 register DINODE *dp;
889
6e884967 890 for (inum = ROOTINO; inum <= lastino; inum++) {
f5262822 891 if (statemap[inum] == DSTATE) {
6e884967
KM
892 pfunc = findino;
893 srchname = "..";
894 savino = inum;
895 do {
896 orphan = inum;
897 if ((dp = ginode()) == NULL)
898 break;
899 filsize = dp->di_size;
900 parentdir = 0;
901 ckinode(dp, DATA);
902 if ((inum = parentdir) == 0)
903 break;
f5262822 904 } while (statemap[inum] == DSTATE);
6e884967
KM
905 inum = orphan;
906 if (linkup() == 1) {
907 thisname = pathp = pathname;
908 *pathp++ = '?';
d2c95d76 909 pfunc = pass2check;
6e884967
KM
910 descend();
911 }
912 inum = savino;
913 }
914 }
d2c95d76 915}
6e884967 916
d2c95d76
BJ
917pass4()
918{
919 register int n;
920 register ino_t *blp;
921
922 pfunc = pass4check;
923 for (inum = ROOTINO; inum <= lastino; inum++) {
f5262822 924 switch (statemap[inum]) {
d2c95d76
BJ
925
926 case FSTATE:
f5262822
BJ
927 n = lncntp[inum];
928 if (n)
6e884967
KM
929 adjust((short)n);
930 else {
931 for (blp = badlncnt;blp < badlnp; blp++)
932 if (*blp == inum) {
933 clri("UNREF", 1);
934 break;
935 }
936 }
937 break;
938
939 case DSTATE:
940 clri("UNREF", 1);
941 break;
942
943 case CLEAR:
944 clri("BAD/DUP", 1);
945 break;
946 }
947 }
8e5c1c7c 948 if (imax - ROOTINO - n_files != sblock.fs_cstotal.cs_nifree) {
6e884967
KM
949 pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
950 if (preen)
951 printf(" (FIXED)\n");
952 if (preen || reply("FIX") == 1) {
bf4c734c 953 sblock.fs_cstotal.cs_nifree = imax - ROOTINO - n_files;
6e884967
KM
954 sbdirty();
955 }
956 }
957 flush(&dfile, &fileblk);
d2c95d76 958}
6e884967 959
d2c95d76
BJ
960pass4check(blk, size)
961 daddr_t blk;
962{
963 register daddr_t *dlp;
964 int res = KEEPON;
965
966 for (; size > 0; blk++, size--) {
f5971be7 967 if (outrange(blk, 1))
d2c95d76
BJ
968 res = SKIP;
969 else if (getbmap(blk)) {
970 for (dlp = duplist; dlp < enddup; dlp++)
971 if (*dlp == blk) {
972 *dlp = *--enddup;
973 return (KEEPON);
974 }
975 clrbmap(blk);
976 n_blks--;
977 }
978 }
979 return (res);
980}
981
982pass5()
983{
984 register int c, n, i, b, d;
f5971be7
BJ
985 short bo[MAXCPG][NRPOS];
986 long botot[MAXCPG];
987 long frsum[MAXFRAG];
988 int blk;
989 daddr_t cbase;
990 int blockbits = (1<<sblock.fs_frag)-1;
d2c95d76 991
0db712b3 992 bcopy(blockmap, freemap, (unsigned)bmapsz);
6e884967 993 dupblk = 0;
6994bf5d 994 n_index = sblock.fs_ncg * (cgdmin(&sblock, 0) - cgtod(&sblock, 0));
6e884967 995 for (c = 0; c < sblock.fs_ncg; c++) {
f5971be7
BJ
996 cbase = cgbase(&sblock, c);
997 bzero(botot, sizeof (botot));
998 bzero(bo, sizeof (bo));
999 bzero(frsum, sizeof (frsum));
f3c028b7 1000 /*
bf541624 1001 * need to account for the super blocks
f3c028b7
KM
1002 * which appear (inaccurately) bad
1003 */
bf541624 1004 n_bad += cgtod(&sblock, c) - cgsblock(&sblock, c);
6994bf5d 1005 if (getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize) == 0)
6e884967 1006 continue;
f5971be7
BJ
1007 if (cgrp.cg_magic != CG_MAGIC) {
1008 pfatal("cg %d: bad magic number\n", c);
1009 bzero((caddr_t)&cgrp, sblock.fs_cgsize);
1010 }
b6407c9d 1011 for (b = 0; b < sblock.fs_fpg; b += sblock.fs_frag) {
f5971be7
BJ
1012 blk = blkmap(&sblock, cgrp.cg_free, b);
1013 if (blk == 0)
1014 continue;
1015 if (blk == blockbits) {
d2c95d76 1016 if (pass5check(cbase+b, sblock.fs_frag) == STOP)
6e884967
KM
1017 goto out5;
1018 /* this is clumsy ... */
d2c95d76
BJ
1019 n_ffree -= sblock.fs_frag;
1020 n_bfree++;
1021 botot[cbtocylno(&sblock, b)]++;
1022 bo[cbtocylno(&sblock, b)]
1023 [cbtorpos(&sblock, b)]++;
f5971be7 1024 continue;
d2c95d76 1025 }
f5971be7
BJ
1026 for (d = 0; d < sblock.fs_frag; d++)
1027 if ((blk & (1<<d)) &&
1028 pass5check(cbase+b+d,1) == STOP)
1029 goto out5;
1030 fragacct(&sblock, blk, frsum, 1);
6e884967 1031 }
f5971be7
BJ
1032 if (bcmp(cgrp.cg_frsum, frsum, sizeof (frsum))) {
1033 if (debug)
1034 for (i = 0; i < sblock.fs_frag; i++)
1035 if (cgrp.cg_frsum[i] != frsum[i])
1036 printf("cg[%d].cg_frsum[%d] have %d calc %d\n",
1037 c, i, cgrp.cg_frsum[i], frsum[i]);
1038 frsumbad++;
d2c95d76 1039 }
f5971be7
BJ
1040 if (bcmp(cgrp.cg_btot, botot, sizeof (botot))) {
1041 if (debug)
1042 for (n = 0; n < sblock.fs_cpg; n++)
1043 if (botot[n] != cgrp.cg_btot[n])
1044 printf("cg[%d].cg_btot[%d] have %d calc %d\n",
1045 c, n, cgrp.cg_btot[n], botot[n]);
1046 offsumbad++;
1047 }
1048 if (bcmp(cgrp.cg_b, bo, sizeof (bo))) {
1049 if (debug)
d2c95d76 1050 for (i = 0; i < NRPOS; i++)
f5971be7
BJ
1051 if (bo[n][i] != cgrp.cg_b[n][i])
1052 printf("cg[%d].cg_b[%d][%d] have %d calc %d\n",
1053 c, n, i, cgrp.cg_b[n][i], bo[n][i]);
1054 offsumbad++;
6e884967
KM
1055 }
1056 }
d2c95d76
BJ
1057out5:
1058 if (dupblk)
1059 pwarn("%d DUP BLKS IN BIT MAPS\n", dupblk);
1060 if (fixcg == 0) {
1061 if ((b = n_blks+n_ffree+sblock.fs_frag*n_bfree+n_index+n_bad) != fmax) {
1062 pwarn("%ld BLK(S) MISSING\n", fmax - b);
1063 fixcg = 1;
1064 } else if (inosumbad + offsumbad + frsumbad + sbsumbad) {
1065 pwarn("SUMMARY INFORMATION %s%s%s%sBAD\n",
1066 inosumbad ? "(INODE FREE) " : "",
1067 offsumbad ? "(BLOCK OFFSETS) " : "",
1068 frsumbad ? "(FRAG SUMMARIES) " : "",
1069 sbsumbad ? "(SUPER BLOCK SUMMARIES) " : "");
1070 fixcg = 1;
1071 } else if (n_ffree != sblock.fs_cstotal.cs_nffree ||
1072 n_bfree != sblock.fs_cstotal.cs_nbfree) {
1073 pwarn("FREE BLK COUNT(S) WRONG IN SUPERBLK");
1074 if (preen)
1075 printf(" (FIXED)\n");
1076 if (preen || reply("FIX") == 1) {
1077 sblock.fs_cstotal.cs_nffree = n_ffree;
1078 sblock.fs_cstotal.cs_nbfree = n_bfree;
1079 sbdirty();
1080 }
1081 }
1082 }
1083 if (fixcg) {
1084 pwarn("BAD CYLINDER GROUPS");
1085 if (preen)
1086 printf(" (SALVAGED)\n");
1087 else if (reply("SALVAGE") == 0)
1088 fixcg = 0;
1089 }
6e884967
KM
1090}
1091
d2c95d76 1092pass5check(blk, size)
6e884967
KM
1093 daddr_t blk;
1094 int size;
1095{
6e884967 1096
f5971be7
BJ
1097 if (outrange(blk, size)) {
1098 fixcg = 1;
1099 if (preen)
1100 pfatal("BAD BLOCKS IN BIT MAPS.");
1101 if (++badblk >= MAXBAD) {
1102 printf("EXCESSIVE BAD BLKS IN BIT MAPS.");
1103 if (reply("CONTINUE") == 0)
1104 errexit("");
1105 return (STOP);
1106 }
1107 }
1108 for (; size > 0; blk++, size--)
1109 if (getfmap(blk)) {
6e884967 1110 fixcg = 1;
7ebb5f4e 1111 ++dupblk;
6e884967
KM
1112 } else {
1113 n_ffree++;
1114 setfmap(blk);
1115 }
f5971be7 1116 return (KEEPON);
6e884967
KM
1117}
1118
d2c95d76
BJ
1119ckinode(dp, flg)
1120 DINODE *dp;
1121 register flg;
1122{
1123 register daddr_t *ap;
1124 register ret;
1125 int (*func)(), n, ndb, size, offset;
1126 ino_t number = inum;
1127 DINODE dino;
1128
1129 if (SPECIAL)
1130 return (KEEPON);
1131 dino = *dp;
1132 func = (flg == ADDR) ? pfunc : dirscan;
1133 ndb = howmany(dino.di_size, sblock.fs_bsize);
1134 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) {
1135 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0)
1136 size = numfrags(&sblock, fragroundup(&sblock, offset));
1137 else
1138 size = sblock.fs_frag;
1139 dnum = number;
1140 if (*ap && (ret = (*func)(*ap, size)) & STOP)
1141 return (ret);
1142 }
1143 for (ap = &dino.di_ib[0], n = 1; n <= 2; ap++, n++) {
1144 dnum = number;
1145 if (*ap) {
1146 ret = iblock(*ap, n, flg,
1147 dino.di_size - sblock.fs_bsize * NDADDR);
1148 if (ret & STOP)
1149 return (ret);
1150 }
1151 }
1152 return (KEEPON);
1153}
1154
1155iblock(blk, ilevel, flg, isize)
1156 daddr_t blk;
1157 register ilevel;
1158 int isize;
1159{
1160 register daddr_t *ap;
1161 register daddr_t *aplim;
1162 register int i, n;
1163 int (*func)(), nif;
1164 BUFAREA ib;
1165
1166 if (flg == ADDR) {
1167 func = pfunc;
1168 if (((n = (*func)(blk, sblock.fs_frag)) & KEEPON) == 0)
1169 return (n);
1170 } else
1171 func = dirscan;
f5971be7 1172 if (outrange(blk, sblock.fs_frag)) /* protect thyself */
d2c95d76
BJ
1173 return (SKIP);
1174 initbarea(&ib);
1175 if (getblk(&ib, blk, sblock.fs_bsize) == NULL)
1176 return (SKIP);
1177 ilevel--;
1178 if (ilevel == 0) {
1179 nif = lblkno(&sblock, isize) + 1;
1180 } else /* ilevel == 1 */ {
1181 nif = isize / (sblock.fs_bsize * NINDIR(&sblock)) + 1;
1182 }
1183 if (nif > NINDIR(&sblock))
1184 nif = NINDIR(&sblock);
1185 aplim = &ib.b_un.b_indir[nif];
1186 for (ap = ib.b_un.b_indir, i = 1; ap < aplim; ap++, i++)
1187 if (*ap) {
1188 if (ilevel > 0)
1189 n = iblock(*ap, ilevel, flg,
1190 isize - i*NINDIR(&sblock)*sblock.fs_bsize);
1191 else
1192 n = (*func)(*ap, sblock.fs_frag);
1193 if (n & STOP)
1194 return (n);
1195 }
1196 return (KEEPON);
1197}
1198
f5971be7 1199outrange(blk, cnt)
6e884967 1200 daddr_t blk;
f5971be7 1201 int cnt;
6e884967
KM
1202{
1203 register int c;
1204
f5971be7 1205 if ((unsigned)(blk+cnt) > fmax)
6e884967 1206 return (1);
f5971be7
BJ
1207 c = dtog(&sblock, blk);
1208 if (blk < cgdmin(&sblock, c)) {
1209 if ((blk+cnt) > cgsblock(&sblock, c)) {
1210 if (debug) {
1211 printf("blk %d < cgdmin %d;",
1212 blk, cgdmin(&sblock, c));
1213 printf(" blk+cnt %d > cgsbase %d\n",
1214 blk+cnt, cgsblock(&sblock, c));
1215 }
1216 return (1);
1217 }
1218 } else {
1219 if ((blk+cnt) > cgbase(&sblock, c+1)) {
1220 if (debug) {
1221 printf("blk %d >= cgdmin %d;",
1222 blk, cgdmin(&sblock, c));
1223 printf(" blk+cnt %d > sblock.fs_fpg %d\n",
1224 blk+cnt, sblock.fs_fpg);
1225 }
1226 return (1);
1227 }
07670f7d 1228 }
6e884967
KM
1229 return (0);
1230}
1231
1232blkerr(s, blk)
1233 daddr_t blk;
1234 char *s;
1235{
f5262822 1236
6e884967
KM
1237 pfatal("%ld %s I=%u", blk, s, inum);
1238 printf("\n");
f5262822 1239 statemap[inum] = CLEAR;
6e884967
KM
1240}
1241
1242descend()
1243{
1244 register DINODE *dp;
1245 register char *savname;
1246 off_t savsize;
1247
f5262822 1248 statemap[inum] = FSTATE;
6e884967
KM
1249 if ((dp = ginode()) == NULL)
1250 return;
1251 savname = thisname;
1252 *pathp++ = '/';
1253 savsize = filsize;
1254 filsize = dp->di_size;
1255 ckinode(dp, DATA);
1256 thisname = savname;
1257 *--pathp = 0;
1258 filsize = savsize;
1259}
1260
24a31719
KM
1261struct dirstuff {
1262 int loc;
1263 int blkno;
1264 int blksiz;
6c6be8f1 1265 ino_t number;
cf8ac751 1266 enum {DONTKNOW, NOFIX, FIX} fix;
24a31719
KM
1267};
1268
6e884967 1269dirscan(blk, nf)
8ebf61ca
KM
1270 daddr_t blk;
1271 int nf;
6e884967 1272{
24a31719 1273 register DIRECT *dp;
24a31719 1274 struct dirstuff dirp;
754cadb5
KM
1275 int blksiz, dsize, n;
1276 char dbuf[DIRBLKSIZ];
6e884967 1277
f5971be7 1278 if (outrange(blk, 1)) {
b6407c9d 1279 filsize -= sblock.fs_bsize;
6e884967
KM
1280 return (SKIP);
1281 }
24a31719
KM
1282 blksiz = nf * sblock.fs_fsize;
1283 dirp.loc = 0;
1284 dirp.blkno = blk;
1285 dirp.blksiz = blksiz;
690f77ba
KM
1286 if (dirp.number != dnum) {
1287 dirp.number = dnum;
cf8ac751 1288 dirp.fix = DONTKNOW;
690f77ba 1289 }
24a31719 1290 for (dp = readdir(&dirp); dp != NULL; dp = readdir(&dirp)) {
754cadb5 1291 dsize = dp->d_reclen;
d2c95d76 1292 bcopy(dp, dbuf, dsize);
754cadb5 1293 if ((n = (*pfunc)(dbuf)) & ALTERD) {
24a31719 1294 if (getblk(&fileblk, blk, blksiz) != NULL) {
d2c95d76 1295 bcopy(dbuf, dp, dsize);
8ebf61ca 1296 dirty(&fileblk);
6e884967
KM
1297 sbdirty();
1298 } else
1299 n &= ~ALTERD;
1300 }
24a31719 1301 if (n & STOP)
6e884967
KM
1302 return (n);
1303 }
1304 return (filsize > 0 ? KEEPON : STOP);
1305}
1306
24a31719
KM
1307/*
1308 * get next entry in a directory.
1309 */
1310DIRECT *
1311readdir(dirp)
1312 register struct dirstuff *dirp;
1313{
754cadb5 1314 register DIRECT *dp, *ndp;
690f77ba 1315 long size;
24a31719
KM
1316
1317 if (getblk(&fileblk, dirp->blkno, dirp->blksiz) == NULL) {
1318 filsize -= dirp->blksiz - dirp->loc;
1319 return NULL;
1320 }
690f77ba
KM
1321 while (dirp->loc % DIRBLKSIZ == 0 && filsize > 0 &&
1322 dirp->loc < dirp->blksiz) {
052efd62 1323 dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
690f77ba
KM
1324 if (dp->d_ino < imax &&
1325 dp->d_namlen <= MAXNAMLEN && dp->d_namlen >= 0 &&
1326 dp->d_reclen > 0 && dp->d_reclen <= DIRBLKSIZ)
1327 break;
1328 dirp->loc += DIRBLKSIZ;
1329 filsize -= DIRBLKSIZ;
cf8ac751 1330 if (dirp->fix == DONTKNOW) {
5ca02310 1331 pfatal("DIRECTORY %D CORRUPTED", dirp->number);
cf8ac751 1332 dirp->fix = NOFIX;
5ca02310 1333 if (reply("SALVAGE") != 0)
cf8ac751 1334 dirp->fix = FIX;
690f77ba 1335 }
cf8ac751 1336 if (dirp->fix != FIX)
24a31719 1337 continue;
690f77ba
KM
1338 dp->d_reclen = DIRBLKSIZ;
1339 dp->d_ino = 0;
1340 dp->d_namlen = 0;
1341 dirty(&fileblk);
1342 }
1343 if (filsize <= 0 || dirp->loc >= dirp->blksiz)
1344 return NULL;
1345 dp = (DIRECT *)(dirblk.b_buf + dirp->loc);
1346 dirp->loc += dp->d_reclen;
1347 filsize -= dp->d_reclen;
1348 ndp = (DIRECT *)(dirblk.b_buf + dirp->loc);
0b2a25e4
KM
1349 if ((filsize <= 0 && dirp->loc % DIRBLKSIZ != 0) ||
1350 (dirp->loc < dirp->blksiz && filsize > 0 &&
690f77ba
KM
1351 (ndp->d_ino >= imax ||
1352 ndp->d_namlen > MAXNAMLEN || ndp->d_namlen < 0 ||
1353 ndp->d_reclen <= 0 ||
0b2a25e4 1354 ndp->d_reclen > DIRBLKSIZ - (dirp->loc % DIRBLKSIZ)))) {
690f77ba
KM
1355 size = DIRBLKSIZ - (dirp->loc % DIRBLKSIZ);
1356 dirp->loc += size;
1357 filsize -= size;
cf8ac751 1358 if (dirp->fix == DONTKNOW) {
5ca02310 1359 pfatal("DIRECTORY %D CORRUPTED", dirp->number);
cf8ac751 1360 dirp->fix = NOFIX;
5ca02310 1361 if (reply("SALVAGE") != 0)
cf8ac751 1362 dirp->fix = FIX;
690f77ba 1363 }
cf8ac751 1364 if (dirp->fix == FIX) {
690f77ba
KM
1365 dp->d_reclen += size;
1366 dirty(&fileblk);
754cadb5 1367 }
24a31719 1368 }
690f77ba 1369 return (dp);
24a31719
KM
1370}
1371
6e884967 1372direrr(s)
8ebf61ca 1373 char *s;
6e884967
KM
1374{
1375 register DINODE *dp;
1376
1377 pwarn("%s ", s);
1378 pinode();
1379 printf("\n");
1380 if ((dp = ginode()) != NULL && ftypeok(dp))
24a31719 1381 pfatal("%s=%s", DIRCT?"DIR":"FILE", pathname);
6e884967
KM
1382 else
1383 pfatal("NAME=%s", pathname);
1384 return (reply("REMOVE"));
1385}
1386
1387adjust(lcnt)
f3c028b7 1388 register short lcnt;
6e884967
KM
1389{
1390 register DINODE *dp;
1391
1392 if ((dp = ginode()) == NULL)
1393 return;
1394 if (dp->di_nlink == lcnt) {
1395 if (linkup() == 0)
1396 clri("UNREF", 0);
1397 }
1398 else {
1399 pwarn("LINK COUNT %s",
24a31719 1400 (lfdir==inum)?lfname:(DIRCT?"DIR":"FILE"));
6e884967
KM
1401 pinode();
1402 printf(" COUNT %d SHOULD BE %d",
1403 dp->di_nlink, dp->di_nlink-lcnt);
1404 if (preen) {
1405 if (lcnt < 0) {
1406 printf("\n");
1407 preendie();
1408 }
1409 printf(" (ADJUSTED)\n");
1410 }
1411 if (preen || reply("ADJUST") == 1) {
1412 dp->di_nlink -= lcnt;
1413 inodirty();
1414 }
1415 }
1416}
1417
1418clri(s, flg)
8ebf61ca 1419 char *s;
6e884967
KM
1420{
1421 register DINODE *dp;
1422
1423 if ((dp = ginode()) == NULL)
1424 return;
1425 if (flg == 1) {
24a31719 1426 pwarn("%s %s", s, DIRCT?"DIR":"FILE");
6e884967
KM
1427 pinode();
1428 }
1429 if (preen || reply("CLEAR") == 1) {
1430 if (preen)
1431 printf(" (CLEARED)\n");
1432 n_files--;
d2c95d76 1433 pfunc = pass4check;
6e884967
KM
1434 ckinode(dp, ADDR);
1435 zapino(dp);
f5262822 1436 statemap[inum] = USTATE;
6e884967
KM
1437 inodirty();
1438 inosumbad++;
1439 }
1440}
1441
6e884967
KM
1442badsb(s)
1443 char *s;
1444{
1445
1446 if (preen)
1447 printf("%s: ", devname);
1448 printf("BAD SUPER BLOCK: %s\n", s);
1449 pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
1450 pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
1451}
1452
1453DINODE *
1454ginode()
1455{
1456 daddr_t iblk;
1457
f3385032
KM
1458 if (inum < ROOTINO || inum > imax) {
1459 if (debug && (inum < 0 || inum > imax))
1460 printf("inum out of range (%d)\n", inum);
6e884967 1461 return (NULL);
f3385032 1462 }
b6407c9d 1463 if (inum < startinum || inum >= startinum + INOPB(&sblock)) {
6994bf5d 1464 iblk = itod(&sblock, inum);
b6407c9d 1465 if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
6e884967
KM
1466 return (NULL);
1467 }
b6407c9d 1468 startinum = (inum / INOPB(&sblock)) * INOPB(&sblock);
6e884967 1469 }
b6407c9d 1470 return (&inoblk.b_un.b_dinode[inum % INOPB(&sblock)]);
6e884967
KM
1471}
1472
1473ftypeok(dp)
1474 DINODE *dp;
1475{
1476 switch (dp->di_mode & IFMT) {
1477
1478 case IFDIR:
1479 case IFREG:
1480 case IFBLK:
1481 case IFCHR:
ea47352d 1482 case IFLNK:
6e884967
KM
1483 return (1);
1484
1485 default:
67272100
KM
1486 if (debug)
1487 printf("bad file type 0%o\n", dp->di_mode);
6e884967
KM
1488 return (0);
1489 }
1490}
1491
1492reply(s)
1493 char *s;
1494{
1495 char line[80];
1496
1497 if (preen)
1498 pfatal("INTERNAL ERROR: GOT TO reply()");
1499 rplyflag = 1;
1500 printf("\n%s? ", s);
1501 if (nflag || dfile.wfdes < 0) {
1502 printf(" no\n\n");
1503 return (0);
1504 }
1505 if (yflag) {
1506 printf(" yes\n\n");
1507 return (1);
1508 }
1509 if (getline(stdin, line, sizeof(line)) == EOF)
1510 errexit("\n");
1511 printf("\n");
1512 if (line[0] == 'y' || line[0] == 'Y')
1513 return (1);
1514 else
1515 return (0);
1516}
1517
1518getline(fp, loc, maxlen)
1519 FILE *fp;
1520 char *loc;
1521{
1522 register n;
1523 register char *p, *lastloc;
1524
1525 p = loc;
1526 lastloc = &p[maxlen-1];
1527 while ((n = getc(fp)) != '\n') {
1528 if (n == EOF)
1529 return (EOF);
1530 if (!isspace(n) && p < lastloc)
1531 *p++ = n;
1532 }
1533 *p = 0;
1534 return (p - loc);
1535}
1536
1537BUFAREA *
1538getblk(bp, blk, size)
1539 daddr_t blk;
1540 register BUFAREA *bp;
1541 int size;
1542{
1543 register struct filecntl *fcp;
b6407c9d 1544 daddr_t dblk;
6e884967
KM
1545
1546 fcp = &dfile;
b6407c9d
KM
1547 dblk = fsbtodb(&sblock, blk);
1548 if (bp->b_bno == dblk)
6e884967
KM
1549 return (bp);
1550 flush(fcp, bp);
b6407c9d
KM
1551 if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
1552 bp->b_bno = dblk;
6e884967
KM
1553 bp->b_size = size;
1554 return (bp);
1555 }
1556 bp->b_bno = (daddr_t)-1;
1557 return (NULL);
1558}
1559
1560flush(fcp, bp)
1561 struct filecntl *fcp;
1562 register BUFAREA *bp;
1563{
1564
1565 if (bp->b_dirty)
1566 bwrite(fcp, bp->b_un.b_buf, bp->b_bno, bp->b_size);
1567 bp->b_dirty = 0;
1568}
1569
1570rwerr(s, blk)
1571 char *s;
1572 daddr_t blk;
1573{
1574
1575 if (preen == 0)
1576 printf("\n");
1577 pfatal("CANNOT %s: BLK %ld", s, blk);
1578 if (reply("CONTINUE") == 0)
1579 errexit("Program terminated\n");
1580}
1581
1582ckfini()
1583{
1584
1585 flush(&dfile, &fileblk);
1586 flush(&dfile, &sblk);
f3c028b7
KM
1587 if (sblk.b_bno != SBLOCK) {
1588 sblk.b_bno = SBLOCK;
1589 sbdirty();
1590 flush(&dfile, &sblk);
1591 }
6e884967
KM
1592 flush(&dfile, &inoblk);
1593 close(dfile.rfdes);
1594 close(dfile.wfdes);
1595}
1596
1597pinode()
1598{
1599 register DINODE *dp;
1600 register char *p;
24a31719 1601 char uidbuf[BUFSIZ];
6e884967
KM
1602 char *ctime();
1603
1604 printf(" I=%u ", inum);
1605 if ((dp = ginode()) == NULL)
1606 return;
1607 printf(" OWNER=");
1608 if (getpw((int)dp->di_uid, uidbuf) == 0) {
1609 for (p = uidbuf; *p != ':'; p++);
1610 *p = 0;
1611 printf("%s ", uidbuf);
1612 }
1613 else {
1614 printf("%d ", dp->di_uid);
1615 }
1616 printf("MODE=%o\n", dp->di_mode);
1617 if (preen)
1618 printf("%s: ", devname);
1619 printf("SIZE=%ld ", dp->di_size);
1620 p = ctime(&dp->di_mtime);
1621 printf("MTIME=%12.12s %4.4s ", p+4, p+20);
1622}
1623
6e884967
KM
1624makecg()
1625{
f3c028b7 1626 int c, blk;
bf541624 1627 daddr_t dbase, d, dlower, dupper, dmax;
6e884967
KM
1628 long i, j, s;
1629 register struct csum *cs;
f3c028b7 1630 register DINODE *dp;
6e884967 1631
0947395d
KM
1632 sblock.fs_cstotal.cs_nbfree = 0;
1633 sblock.fs_cstotal.cs_nffree = 0;
1634 sblock.fs_cstotal.cs_nifree = 0;
1635 sblock.fs_cstotal.cs_ndir = 0;
6e884967 1636 for (c = 0; c < sblock.fs_ncg; c++) {
6994bf5d 1637 dbase = cgbase(&sblock, c);
6e884967 1638 dmax = dbase + sblock.fs_fpg;
8f99f49c 1639 if (dmax > sblock.fs_size) {
bf4c734c 1640 for ( ; dmax >= sblock.fs_size; dmax--)
2e9860b5 1641 clrbit(cgrp.cg_free, dmax - dbase);
8f99f49c
KM
1642 dmax++;
1643 }
bf541624
KM
1644 dlower = cgsblock(&sblock, c) - dbase;
1645 dupper = cgdmin(&sblock, c) - dbase;
b6407c9d 1646 cs = &sblock.fs_cs(&sblock, c);
6e884967
KM
1647 cgrp.cg_time = time(0);
1648 cgrp.cg_magic = CG_MAGIC;
1649 cgrp.cg_cgx = c;
67272100
KM
1650 if (c == sblock.fs_ncg - 1)
1651 cgrp.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
1652 else
1653 cgrp.cg_ncyl = sblock.fs_cpg;
6e884967
KM
1654 cgrp.cg_niblk = sblock.fs_ipg;
1655 cgrp.cg_ndblk = dmax - dbase;
0947395d
KM
1656 cgrp.cg_cs.cs_ndir = 0;
1657 cgrp.cg_cs.cs_nffree = 0;
1658 cgrp.cg_cs.cs_nbfree = 0;
1659 cgrp.cg_cs.cs_nifree = 0;
bf541624
KM
1660 cgrp.cg_rotor = 0;
1661 cgrp.cg_frotor = 0;
92ea6158 1662 cgrp.cg_irotor = 0;
b6407c9d 1663 for (i = 0; i < sblock.fs_frag; i++)
f3c028b7 1664 cgrp.cg_frsum[i] = 0;
6e884967 1665 inum = sblock.fs_ipg * c;
f3c028b7 1666 for (i = 0; i < sblock.fs_ipg; inum++, i++) {
bf4c734c
KM
1667 cgrp.cg_cs.cs_nifree++;
1668 clrbit(cgrp.cg_iused, i);
f3c028b7
KM
1669 dp = ginode();
1670 if (dp == NULL)
1671 continue;
1672 if (ALLOC) {
24a31719 1673 if (DIRCT)
0947395d 1674 cgrp.cg_cs.cs_ndir++;
bf4c734c 1675 cgrp.cg_cs.cs_nifree--;
f3c028b7
KM
1676 setbit(cgrp.cg_iused, i);
1677 continue;
1678 }
6e884967
KM
1679 }
1680 while (i < MAXIPG) {
1681 clrbit(cgrp.cg_iused, i);
1682 i++;
1683 }
bf4c734c
KM
1684 if (c == 0)
1685 for (i = 0; i < ROOTINO; i++) {
1686 setbit(cgrp.cg_iused, i);
1687 cgrp.cg_cs.cs_nifree--;
1688 }
43f6367c
KM
1689 for (s = 0; s < MAXCPG; s++) {
1690 cgrp.cg_btot[s] = 0;
6e884967
KM
1691 for (i = 0; i < NRPOS; i++)
1692 cgrp.cg_b[s][i] = 0;
43f6367c 1693 }
6e884967 1694 if (c == 0) {
bf541624 1695 dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
6e884967 1696 }
bf541624 1697 for (d = dlower; d < dupper; d++)
6e884967 1698 clrbit(cgrp.cg_free, d);
bf541624
KM
1699 for (d = 0; (d + sblock.fs_frag) <= dmax - dbase;
1700 d += sblock.fs_frag) {
6e884967 1701 j = 0;
b6407c9d 1702 for (i = 0; i < sblock.fs_frag; i++) {
bf541624
KM
1703 if (!getbmap(dbase + d + i)) {
1704 setbit(cgrp.cg_free, d + i);
6e884967
KM
1705 j++;
1706 } else
1707 clrbit(cgrp.cg_free, d+i);
1708 }
b6407c9d 1709 if (j == sblock.fs_frag) {
0947395d 1710 cgrp.cg_cs.cs_nbfree++;
43f6367c 1711 cgrp.cg_btot[cbtocylno(&sblock, d)]++;
aca50d72
KM
1712 cgrp.cg_b[cbtocylno(&sblock, d)]
1713 [cbtorpos(&sblock, d)]++;
f3c028b7 1714 } else if (j > 0) {
0947395d 1715 cgrp.cg_cs.cs_nffree += j;
bf541624 1716 blk = blkmap(&sblock, cgrp.cg_free, d);
b6407c9d 1717 fragacct(&sblock, blk, cgrp.cg_frsum, 1);
f3c028b7 1718 }
6e884967 1719 }
f3c028b7 1720 for (j = d; d < dmax - dbase; d++) {
bf541624 1721 if (!getbmap(dbase + d)) {
6e884967 1722 setbit(cgrp.cg_free, d);
0947395d 1723 cgrp.cg_cs.cs_nffree++;
6e884967
KM
1724 } else
1725 clrbit(cgrp.cg_free, d);
1726 }
67272100
KM
1727 for (; d % sblock.fs_frag != 0; d++)
1728 clrbit(cgrp.cg_free, d);
f3c028b7 1729 if (j != d) {
bf541624 1730 blk = blkmap(&sblock, cgrp.cg_free, j);
b6407c9d 1731 fragacct(&sblock, blk, cgrp.cg_frsum, 1);
f3c028b7 1732 }
67272100
KM
1733 for (d /= sblock.fs_frag; d < MAXBPG(&sblock); d ++)
1734 clrblock(&sblock, cgrp.cg_free, d);
0947395d
KM
1735 sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree;
1736 sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree;
1737 sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
1738 sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
1739 *cs = cgrp.cg_cs;
6994bf5d 1740 bwrite(&dfile, &cgrp, fsbtodb(&sblock, cgtod(&sblock, c)),
3352e84a 1741 sblock.fs_cgsize);
6e884967 1742 }
bf541624
KM
1743 for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
1744 bwrite(&dfile, (char *)sblock.fs_csp[j],
1745 fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
1746 sblock.fs_cssize - i < sblock.fs_bsize ?
1747 sblock.fs_cssize - i : sblock.fs_bsize);
c2a050cf 1748 }
6e884967
KM
1749 sblock.fs_ronly = 0;
1750 sblock.fs_fmod = 0;
1751 sbdirty();
1752}
1753
1754findino(dirp)
1755 register DIRECT *dirp;
1756{
6e884967
KM
1757 if (dirp->d_ino == 0)
1758 return (KEEPON);
24a31719
KM
1759 if (!strcmp(dirp->d_name, srchname)) {
1760 if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
1761 parentdir = dirp->d_ino;
1762 return (STOP);
6e884967
KM
1763 }
1764 return (KEEPON);
1765}
1766
1767mkentry(dirp)
1768 register DIRECT *dirp;
1769{
1770 register ino_t in;
1771 register char *p;
754cadb5
KM
1772 DIRECT newent;
1773 int newlen, oldlen;
6e884967 1774
754cadb5
KM
1775 newent.d_namlen = 11;
1776 newlen = DIRSIZ(&newent);
1777 if (dirp->d_ino != 0)
1778 oldlen = DIRSIZ(dirp);
1779 else
1780 oldlen = 0;
1781 if (dirp->d_reclen - oldlen < newlen)
6e884967 1782 return (KEEPON);
754cadb5
KM
1783 newent.d_reclen = dirp->d_reclen - oldlen;
1784 dirp->d_reclen = oldlen;
1785 dirp = (struct direct *)(((char *)dirp) + oldlen);
6e884967 1786 dirp->d_ino = orphan;
754cadb5
KM
1787 dirp->d_reclen = newent.d_reclen;
1788 p = &dirp->d_name[2];
1789 for (in = imax; in > 0; in /= 10)
1790 p++;
6e884967 1791 *--p = 0;
754cadb5
KM
1792 dirp->d_namlen = p - dirp->d_name;
1793 in = orphan;
6e884967
KM
1794 while (p > dirp->d_name) {
1795 *--p = (in % 10) + '0';
1796 in /= 10;
1797 }
1798 *p = '#';
1799 return (ALTERD|STOP);
1800}
1801
1802chgdd(dirp)
1803 register DIRECT *dirp;
1804{
1805 if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
1806 dirp->d_name[2] == 0) {
1807 dirp->d_ino = lfdir;
1808 return (ALTERD|STOP);
1809 }
1810 return (KEEPON);
1811}
1812
1813linkup()
1814{
1815 register DINODE *dp;
1816 register lostdir;
1817 register ino_t pdir;
1818
1819 if ((dp = ginode()) == NULL)
1820 return (0);
24a31719 1821 lostdir = DIRCT;
6e884967
KM
1822 pdir = parentdir;
1823 pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
1824 pinode();
1825 if (preen && dp->di_size == 0)
1826 return (0);
1827 if (preen)
1828 printf(" (RECONNECTED)\n");
1829 else
1830 if (reply("RECONNECT") == 0)
1831 return (0);
1832 orphan = inum;
1833 if (lfdir == 0) {
1834 inum = ROOTINO;
1835 if ((dp = ginode()) == NULL) {
1836 inum = orphan;
1837 return (0);
1838 }
1839 pfunc = findino;
1840 srchname = lfname;
1841 filsize = dp->di_size;
1842 parentdir = 0;
1843 ckinode(dp, DATA);
1844 inum = orphan;
1845 if ((lfdir = parentdir) == 0) {
1846 pfatal("SORRY. NO lost+found DIRECTORY");
1847 printf("\n\n");
1848 return (0);
1849 }
1850 }
1851 inum = lfdir;
f5262822 1852 if ((dp = ginode()) == NULL || !DIRCT || statemap[inum] != FSTATE) {
6e884967
KM
1853 inum = orphan;
1854 pfatal("SORRY. NO lost+found DIRECTORY");
1855 printf("\n\n");
1856 return (0);
1857 }
3352e84a
KM
1858 if (fragoff(&sblock, dp->di_size)) {
1859 dp->di_size = fragroundup(&sblock, dp->di_size);
6e884967
KM
1860 inodirty();
1861 }
1862 filsize = dp->di_size;
1863 inum = orphan;
1864 pfunc = mkentry;
1865 if ((ckinode(dp, DATA) & ALTERD) == 0) {
1866 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
1867 printf("\n\n");
1868 return (0);
1869 }
f5262822 1870 lncntp[inum]--;
6e884967
KM
1871 if (lostdir) {
1872 pfunc = chgdd;
1873 dp = ginode();
1874 filsize = dp->di_size;
1875 ckinode(dp, DATA);
1876 inum = lfdir;
1877 if ((dp = ginode()) != NULL) {
1878 dp->di_nlink++;
1879 inodirty();
f5262822 1880 lncntp[inum]++;
6e884967
KM
1881 }
1882 inum = orphan;
1883 pwarn("DIR I=%u CONNECTED. ", orphan);
1884 printf("PARENT WAS I=%u\n", pdir);
1885 if (preen == 0)
1886 printf("\n");
1887 }
1888 return (1);
1889}
1890
1891bread(fcp, buf, blk, size)
1892 daddr_t blk;
1893 register struct filecntl *fcp;
1894 register size;
1895 char *buf;
1896{
5e01ca34 1897 if (lseek(fcp->rfdes, dbtob(blk), 0) < 0)
6e884967
KM
1898 rwerr("SEEK", blk);
1899 else if (read(fcp->rfdes, buf, size) == size)
1900 return (1);
1901 rwerr("READ", blk);
1902 return (0);
1903}
1904
1905bwrite(fcp, buf, blk, size)
1906 daddr_t blk;
1907 register struct filecntl *fcp;
1908 register size;
1909 char *buf;
1910{
1911
1912 if (fcp->wfdes < 0)
1913 return (0);
5e01ca34 1914 if (lseek(fcp->wfdes, dbtob(blk), 0) < 0)
6e884967
KM
1915 rwerr("SEEK", blk);
1916 else if (write(fcp->wfdes, buf, size) == size) {
1917 fcp->mod = 1;
1918 return (1);
1919 }
1920 rwerr("WRITE", blk);
1921 return (0);
1922}
1923
1924catch()
1925{
1926
1927 ckfini();
1928 exit(12);
1929}
b6407c9d 1930
d2c95d76
BJ
1931char *
1932unrawname(cp)
1933 char *cp;
1934{
1935 char *dp = rindex(cp, '/');
1936 struct stat stb;
1937
1938 if (dp == 0)
1939 return (cp);
1940 if (stat(cp, &stb) < 0)
1941 return (cp);
1942 if ((stb.st_mode&S_IFMT) != S_IFCHR)
1943 return (cp);
1944 if (*(dp+1) != 'r')
1945 return (cp);
1946 strcpy(dp+1, dp+2);
1947 return (cp);
1948}
1949
1950char *
1951rawname(cp)
1952 char *cp;
1953{
1954 static char rawbuf[32];
1955 char *dp = rindex(cp, '/');
1956
1957 if (dp == 0)
1958 return (0);
1959 *dp = 0;
1960 strcpy(rawbuf, cp);
1961 *dp = '/';
1962 strcat(rawbuf, "/r");
1963 strcat(rawbuf, dp+1);
1964 return (rawbuf);
1965}
1966
1967/* VARARGS1 */
1968error(s1, s2, s3, s4)
1969 char *s1;
1970{
4d308541 1971
d2c95d76
BJ
1972 printf(s1, s2, s3, s4);
1973}
4d308541 1974
d2c95d76
BJ
1975/* VARARGS1 */
1976errexit(s1, s2, s3, s4)
1977 char *s1;
1978{
1979 error(s1, s2, s3, s4);
1980 exit(8);
1981}
4d308541
KM
1982
1983/*
d2c95d76 1984 * An inconsistency occured which shouldn't during normal operations.
af5ba2f8 1985 * Die if preening, otherwise just printf.
4d308541 1986 */
d2c95d76
BJ
1987/* VARARGS1 */
1988pfatal(s, a1, a2, a3)
1989 char *s;
1990{
4d308541 1991
d2c95d76
BJ
1992 if (preen) {
1993 printf("%s: ", devname);
1994 printf(s, a1, a2, a3);
1995 printf("\n");
1996 preendie();
1997 }
1998 printf(s, a1, a2, a3);
1999}
4d308541 2000
d2c95d76
BJ
2001preendie()
2002{
4d308541 2003
d2c95d76
BJ
2004 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
2005 exit(8);
2006}
4d308541
KM
2007
2008/*
d2c95d76
BJ
2009 * Pwarn is like printf when not preening,
2010 * or a warning (preceded by filename) when preening.
4d308541 2011 */
d2c95d76
BJ
2012/* VARARGS1 */
2013pwarn(s, a1, a2, a3, a4, a5, a6)
2014 char *s;
2015{
2016
2017 if (preen)
2018 printf("%s: ", devname);
2019 printf(s, a1, a2, a3, a4, a5, a6);
2020}
9a4020f4
BJ
2021
2022panic(s)
2023 char *s;
2024{
2025
2026 pfatal("internal inconsistency: %s\n");
2027 exit(12);
2028}