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