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