BSD 4 release
[unix-history] / usr / src / cmd / fsck.c
CommitLineData
31cef89c
BJ
1static char *sccsid = "@(#)fsck.c 4.10 (Berkeley) 11/15/80";
2#include <stdio.h>
3#include <ctype.h>
4#include <sys/param.h>
5#include <sys/filsys.h>
6#include <sys/dir.h>
7#include <sys/fblk.h>
8#include <sys/ino.h>
9#include <sys/inode.h>
10#include <sys/stat.h>
11#include <fstab.h>
12
13typedef int (*SIG_TYP)();
14
15#define NDIRECT (BSIZE/sizeof(struct direct))
16#define SPERB (BSIZE/sizeof(short))
17
18#define NO 0
19#define YES 1
20
21#define MAXDUP 10 /* limit on dup blks (per inode) */
22#define MAXBAD 10 /* limit on bad blks (per inode) */
23
24#define STEPSIZE 9 /* default step for freelist spacing */
25#define CYLSIZE 400 /* default cyl size for spacing */
26#define MAXCYL 500 /* maximum cylinder size */
27
28#define BITSPB 8 /* number bits per byte */
29#define BITSHIFT 3 /* log2(BITSPB) */
30#define BITMASK 07 /* BITSPB-1 */
31#define LSTATE 2 /* bits per inode state */
32#define STATEPB (BITSPB/LSTATE) /* inode states per byte */
33#define USTATE 0 /* inode not allocated */
34#define FSTATE 01 /* inode is file */
35#define DSTATE 02 /* inode is directory */
36#define CLEAR 03 /* inode is to be cleared */
37#define SMASK 03 /* mask for inode state */
38
39typedef struct dinode DINODE;
40typedef struct direct DIRECT;
41
42#define ALLOC ((dp->di_mode & IFMT) != 0)
43#define DIR ((dp->di_mode & IFMT) == IFDIR)
44#define REG ((dp->di_mode & IFMT) == IFREG)
45#define BLK ((dp->di_mode & IFMT) == IFBLK)
46#define CHR ((dp->di_mode & IFMT) == IFCHR)
47#define MPC ((dp->di_mode & IFMT) == IFMPC)
48#define MPB ((dp->di_mode & IFMT) == IFMPB)
49#define SPECIAL (BLK || CHR || MPC || MPB)
50
51#define NINOBLK 11 /* num blks for raw reading */
52#define MAXRAW 110 /* largest raw read (in blks) */
53daddr_t startib; /* blk num of first in raw area */
54unsigned niblk; /* num of blks in raw area */
55
56struct bufarea {
57 struct bufarea *b_next; /* must be first */
58 daddr_t b_bno;
59 union {
60 char b_buf[BSIZE]; /* buffer space */
61 short b_lnks[SPERB]; /* link counts */
62 daddr_t b_indir[NINDIR]; /* indirect block */
63 struct filsys b_fs; /* super block */
64 struct fblk b_fb; /* free block */
65 struct dinode b_dinode[INOPB]; /* inode block */
66 DIRECT b_dir[NDIRECT]; /* directory */
67 } b_un;
68 char b_dirty;
69};
70
71typedef struct bufarea BUFAREA;
72
73BUFAREA inoblk; /* inode blocks */
74BUFAREA fileblk; /* other blks in filesys */
75BUFAREA sblk; /* file system superblock */
76BUFAREA *poolhead; /* ptr to first buffer in pool */
77
78#define initbarea(x) (x)->b_dirty = 0;(x)->b_bno = (daddr_t)-1
79#define dirty(x) (x)->b_dirty = 1
80#define inodirty() inoblk.b_dirty = 1
81#define fbdirty() fileblk.b_dirty = 1
82#define sbdirty() sblk.b_dirty = 1
83
84#define freeblk fileblk.b_un.b_fb
85#define dirblk fileblk.b_un
86#define superblk sblk.b_un.b_fs
87
88struct filecntl {
89 int rfdes;
90 int wfdes;
91 int mod;
92};
93
94struct filecntl dfile; /* file descriptors for filesys */
95struct filecntl sfile; /* file descriptors for scratch file */
96
97typedef unsigned MEMSIZE;
98
99MEMSIZE memsize; /* amt of memory we got */
100#ifdef pdp11
101#define MAXDATA ((MEMSIZE)54*1024)
102#endif
103#ifdef vax
104#define MAXDATA ((MEMSIZE)400*1024)
105#endif
106
107#define DUPTBLSIZE 100 /* num of dup blocks to remember */
108daddr_t duplist[DUPTBLSIZE]; /* dup block table */
109daddr_t *enddup; /* next entry in dup table */
110daddr_t *muldup; /* multiple dups part of table */
111
112#define MAXLNCNT 20 /* num zero link cnts to remember */
113ino_t badlncnt[MAXLNCNT]; /* table of inos with zero link cnts */
114ino_t *badlnp; /* next entry in table */
115
116char sflag; /* salvage free block list */
117char csflag; /* salvage free block list (conditional) */
118char nflag; /* assume a no response */
119char yflag; /* assume a yes response */
120char tflag; /* scratch file specified */
121char preen; /* just fix normal inconsistencies */
122char rplyflag; /* any questions asked? */
123char hotroot; /* checking root device */
124char rawflg; /* read raw device */
125char rmscr; /* remove scratch file when done */
126char fixfree; /* corrupted free list */
127char *membase; /* base of memory we get */
128char *blkmap; /* ptr to primary blk allocation map */
129char *freemap; /* ptr to secondary blk allocation map */
130char *statemap; /* ptr to inode state table */
131char *pathp; /* pointer to pathname position */
132char *thisname; /* ptr to current pathname component */
133char *srchname; /* name being searched for in dir */
134char pathname[200];
135char scrfile[80];
136char *lfname = "lost+found";
137char *checklist = FSTAB;
138
139short *lncntp; /* ptr to link count table */
140
141int cylsize; /* num blocks per cylinder */
142int stepsize; /* num blocks for spacing purposes */
143int badblk; /* num of bad blks seen (per inode) */
144int dupblk; /* num of dup blks seen (per inode) */
145int (*pfunc)(); /* function to call to chk blk */
146
147ino_t inum; /* inode we are currently working on */
148ino_t imax; /* number of inodes */
149ino_t parentdir; /* i number of parent directory */
150ino_t lastino; /* hiwater mark of inodes */
151ino_t lfdir; /* lost & found directory */
152ino_t orphan; /* orphaned inode */
153
154off_t filsize; /* num blks seen in file */
155off_t maxblk; /* largest logical blk in file */
156off_t bmapsz; /* num chars in blkmap */
157
158daddr_t smapblk; /* starting blk of state map */
159daddr_t lncntblk; /* starting blk of link cnt table */
160daddr_t fmapblk; /* starting blk of free map */
161daddr_t n_free; /* number of free blocks */
162daddr_t n_blks; /* number of blocks used */
163daddr_t n_files; /* number of files seen */
164daddr_t fmin; /* block number of the first data block */
165daddr_t fmax; /* number of blocks in the volume */
166
167#define howmany(x,y) (((x)+((y)-1))/(y))
168#define roundup(x,y) ((((x)+((y)-1))/(y))*(y))
169#define outrange(x) (x < fmin || x >= fmax)
170#define zapino(x) clear((char *)(x),sizeof(DINODE))
171
172#define setlncnt(x) dolncnt(x,0)
173#define getlncnt() dolncnt(0,1)
174#define declncnt() dolncnt(0,2)
175
176#define setbmap(x) domap(x,0)
177#define getbmap(x) domap(x,1)
178#define clrbmap(x) domap(x,2)
179
180#define setfmap(x) domap(x,0+4)
181#define getfmap(x) domap(x,1+4)
182#define clrfmap(x) domap(x,2+4)
183
184#define setstate(x) dostate(x,0)
185#define getstate() dostate(0,1)
186
187#define DATA 1
188#define ADDR 0
189#define ALTERD 010
190#define KEEPON 04
191#define SKIP 02
192#define STOP 01
193
194int (*signal())();
195long lseek();
196long time();
197DINODE *ginode();
198BUFAREA *getblk();
199BUFAREA *search();
200int dirscan();
201int findino();
202int catch();
203int mkentry();
204int chgdd();
205int pass1();
206int pass1b();
207int pass2();
208int pass3();
209int pass4();
210int pass5();
211
212char *devname;
213
214main(argc,argv)
215int argc;
216char *argv[];
217{
218 register FILE *fp;
219 register n;
220 register char *p;
221 char filename[50];
222 char *sbrk();
223
224 sync();
225 while(--argc > 0 && **++argv == '-') {
226 switch(*++*argv) {
227 case 'p':
228 preen++;
229 break;
230 case 't':
231 case 'T':
232 tflag++;
233 if(**++argv == '-' || --argc <= 0)
234 errexit("Bad -t option\n");
235 p = scrfile;
236 while(*p++ = **argv)
237 (*argv)++;
238 break;
239 case 's': /* salvage flag */
240 stype(++*argv);
241 sflag++;
242 break;
243 case 'S': /* conditional salvage */
244 stype(++*argv);
245 csflag++;
246 break;
247 case 'n': /* default no answer flag */
248 case 'N':
249 nflag++;
250 yflag = 0;
251 break;
252 case 'y': /* default yes answer flag */
253 case 'Y':
254 yflag++;
255 nflag = 0;
256 break;
257 default:
258 errexit("%c option?\n",**argv);
259 }
260 }
261 if(nflag && (sflag || csflag))
262 errexit("Incompatible options: -n and -%s\n",sflag?"s":"S");
263 if(sflag && csflag)
264 sflag = 0;
265 memsize = (MEMSIZE)sbrk(0);
266 memsize = MAXDATA - memsize - sizeof(int);
267 while(memsize >= 2*sizeof(BUFAREA) &&
268 (membase = sbrk(memsize)) == (char *)-1)
269 memsize -= 1024;
270 if(memsize < 2*sizeof(BUFAREA))
271 errexit("Can't get memory\n");
272 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
273 signal(SIGINT, catch);
274 if(argc) { /* arg list has file names */
275 while(argc-- > 0){
276 hotroot = 0;
277 check(*argv++);
278 }
279 }
280 else { /* use default checklist */
281 struct fstab *fsp;
282 int pid, passno, anygtr, sumstatus = 0;
283 passno = 1;
284 do {
285 anygtr = 0;
286 if (setfsent() == 0)
287 errexit("Can't open checklist file: %s\n",
288 FSTAB);
289 while ( (fsp = getfsent()) != 0){
290 if (strcmp(fsp->fs_type, FSTAB_RW) &&
291 strcmp(fsp->fs_type, FSTAB_RO))
292 continue;
293 if (preen == 0 ||
294 passno == 1 && fsp->fs_passno == passno) {
295 if (blockcheck(fsp->fs_spec) == NO &&
296 preen)
297 exit(8);
298 } else if (fsp->fs_passno > passno)
299 anygtr = 1;
300 else if (fsp->fs_passno == passno) {
301 pid = fork();
302 if (pid < 0) {
303 perror("fork");
304 exit(8);
305 }
306 if (pid == 0)
307 if (blockcheck(fsp->fs_spec)==NO)
308 exit(8);
309 else
310 exit(0);
311 }
312 }
313 if (preen) {
314 int status;
315 while (wait(&status) != -1)
316 sumstatus |= status;
317 }
318 passno++;
319 } while (anygtr);
320 if (sumstatus)
321 exit(8);
322 endfsent();
323 }
324 exit(0);
325}
326
327char *rawname(), *rindex(), *unrawname();
328
329blockcheck(name)
330 char *name;
331{
332 struct stat stat_slash, stat_block, stat_char;
333 char *raw;
334 int looped = 0;
335
336 hotroot = 0;
337 if (stat("/", &stat_slash) < 0){
338 error("Can't stat root\n");
339 return(NO);
340 }
341 retry:
342 if (stat(name, &stat_block) < 0){
343 error("Can't stat %s\n", name);
344 return(NO);
345 }
346 if (stat_block.st_mode & S_IFBLK){
347 raw = rawname(name);
348 if (stat(raw, &stat_char) < 0){
349 error("Can't stat %s\n", raw);
350 return(NO);
351 }
352 if (stat_char.st_mode & S_IFCHR){
353 if (stat_slash.st_dev == stat_block.st_rdev) {
354 hotroot++;
355 raw = unrawname(name);
356 }
357 check(raw);
358 return(YES);
359 } else {
360 error("%s is not a character device\n", raw);
361 return(NO);
362 }
363 } else
364 if (stat_block.st_mode & S_IFCHR){
365 if (looped) {
366 error("Can't make sense out of name %s\n", name);
367 return(NO);
368 }
369 name = unrawname(name);
370 looped++;
371 goto retry;
372 }
373 error("Can't make sense out of name %s\n", name);
374 return(NO);
375}
376
377char *
378unrawname(cp)
379 char *cp;
380{
381 char *dp = rindex(cp, '/');
382 struct stat stb;
383 if (dp == 0)
384 return(cp);
385 if (stat(cp, &stb) < 0)
386 return(cp);
387 if ((stb.st_mode&S_IFMT) != S_IFCHR)
388 return(cp);
389 if (*(dp+1) != 'r')
390 return(cp);
391 strcpy(dp+1, dp+2);
392 return(cp);
393}
394
395char *
396rawname(cp)
397 char *cp;
398{
399 static char rawbuf[32];
400 char *dp = rindex(cp, '/');
401
402 if (dp == 0)
403 return (0);
404 *dp = 0;
405 strcpy(rawbuf, cp);
406 *dp = '/';
407 strcat(rawbuf, "/r");
408 strcat(rawbuf, dp+1);
409 return (rawbuf);
410}
411
412check(dev)
413char *dev;
414{
415
416 devname = dev;
417 check1(dev);
418 devname = 0;
419}
420
421check1(dev)
422char *dev;
423{
424 register DINODE *dp;
425 register n;
426 register ino_t *blp;
427 ino_t savino;
428 daddr_t blk;
429 BUFAREA *bp1, *bp2;
430
431 if(setup(dev) == NO)
432 return;
433 if (preen==0) {
434 printf("** Checking %s %s", dev,
435 hotroot?"(ROOT FILE SYSTEM)\n":"\n");
436 printf("** Phase 1 - Check Blocks and Sizes\n");
437 }
438 pfunc = pass1;
439 for(inum = 1; inum <= imax; inum++) {
440 if((dp = ginode()) == NULL)
441 continue;
442 if(ALLOC) {
443 lastino = inum;
444 if(ftypeok(dp) == NO) {
445 pfatal("UNKNOWN FILE TYPE I=%u",inum);
446 if(reply("CLEAR") == YES) {
447 zapino(dp);
448 inodirty();
449 }
450 continue;
451 }
452 n_files++;
453 if(setlncnt(dp->di_nlink) <= 0) {
454 if(badlnp < &badlncnt[MAXLNCNT])
455 *badlnp++ = inum;
456 else {
457 pfatal("LINK COUNT TABLE OVERFLOW");
458 if(reply("CONTINUE") == NO)
459 errexit("");
460 }
461 }
462 setstate(DIR ? DSTATE : FSTATE);
463 badblk = dupblk = 0;
464 filsize = 0;
465 maxblk = 0;
466 ckinode(dp,ADDR);
467 if((n = getstate()) == DSTATE || n == FSTATE)
468 sizechk(dp);
469 }
470 else if(dp->di_mode != 0) {
471 pfatal("PARTIALLY ALLOCATED INODE I=%u",inum);
472 if(reply("CLEAR") == YES) {
473 zapino(dp);
474 inodirty();
475 }
476 }
477 }
478
479
480 if(enddup != &duplist[0]) {
481 if (preen)
482 pfatal("INTERNAL ERROR: dups with -p");
483 printf("** Phase 1b - Rescan For More DUPS\n");
484 pfunc = pass1b;
485 for(inum = 1; inum <= lastino; inum++) {
486 if(getstate() != USTATE && (dp = ginode()) != NULL)
487 if(ckinode(dp,ADDR) & STOP)
488 break;
489 }
490 }
491 if(rawflg) {
492 if(inoblk.b_dirty)
493 bwrite(&dfile,membase,startib,(int)niblk*BSIZE);
494 inoblk.b_dirty = 0;
495 if(poolhead) {
496 clear(membase,niblk*BSIZE);
497 for(bp1 = poolhead;bp1->b_next;bp1 = bp1->b_next);
498 bp2 = &((BUFAREA *)membase)[(niblk*BSIZE)/sizeof(BUFAREA)];
499 while(--bp2 >= (BUFAREA *)membase) {
500 initbarea(bp2);
501 bp2->b_next = bp1->b_next;
502 bp1->b_next = bp2;
503 }
504 }
505 rawflg = 0;
506
507 }
508
509
510 if (preen == 0)
511 printf("** Phase 2 - Check Pathnames\n");
512 inum = ROOTINO;
513 thisname = pathp = pathname;
514 pfunc = pass2;
515 switch(getstate()) {
516 case USTATE:
517 errexit("ROOT INODE UNALLOCATED. TERMINATING.\n");
518 case FSTATE:
519 pfatal("ROOT INODE NOT DIRECTORY");
520 if(reply("FIX") == NO || (dp = ginode()) == NULL)
521 errexit("");
522 dp->di_mode &= ~IFMT;
523 dp->di_mode |= IFDIR;
524 inodirty();
525 setstate(DSTATE);
526 case DSTATE:
527 descend();
528 break;
529 case CLEAR:
530 pfatal("DUPS/BAD IN ROOT INODE");
531 printf("\n");
532 if(reply("CONTINUE") == NO)
533 errexit("");
534 setstate(DSTATE);
535 descend();
536 }
537
538
539 if (preen == 0)
540 printf("** Phase 3 - Check Connectivity\n");
541 for(inum = ROOTINO; inum <= lastino; inum++) {
542 if(getstate() == DSTATE) {
543 pfunc = findino;
544 srchname = "..";
545 savino = inum;
546 do {
547 orphan = inum;
548 if((dp = ginode()) == NULL)
549 break;
550 filsize = dp->di_size;
551 parentdir = 0;
552 ckinode(dp,DATA);
553 if((inum = parentdir) == 0)
554 break;
555 } while(getstate() == DSTATE);
556 inum = orphan;
557 if(linkup() == YES) {
558 thisname = pathp = pathname;
559 *pathp++ = '?';
560 pfunc = pass2;
561 descend();
562 }
563 inum = savino;
564 }
565 }
566
567
568 if (preen == 0)
569 printf("** Phase 4 - Check Reference Counts\n");
570 pfunc = pass4;
571 for(inum = ROOTINO; inum <= lastino; inum++) {
572 switch(getstate()) {
573 case FSTATE:
574 if(n = getlncnt())
575 adjust((short)n);
576 else {
577 for(blp = badlncnt;blp < badlnp; blp++)
578 if(*blp == inum) {
579 clri("UNREF",YES);
580 break;
581 }
582 }
583 break;
584 case DSTATE:
585 clri("UNREF",YES);
586 break;
587 case CLEAR:
588 clri("BAD/DUP",YES);
589 }
590 }
591 if(imax - n_files != superblk.s_tinode) {
592 pwarn("FREE INODE COUNT WRONG IN SUPERBLK");
593 if (preen)
594 printf(" (FIXED)\n");
595 if (preen || reply("FIX") == YES) {
596 superblk.s_tinode = imax - n_files;
597 sbdirty();
598 }
599 }
600 flush(&dfile,&fileblk);
601
602
603 if (preen == 0)
604 printf("** Phase 5 - Check Free List ");
605 if(sflag || (csflag && rplyflag == 0)) {
606 if (preen == 0)
607 printf("(Ignored)\n");
608 fixfree = 1;
609 }
610 else {
611 if (preen == 0)
612 printf("\n");
613 if(freemap)
614 copy(blkmap,freemap,(MEMSIZE)bmapsz);
615 else {
616 for(blk = 0; blk < fmapblk; blk++) {
617 bp1 = getblk((BUFAREA *)NULL,blk);
618 bp2 = getblk((BUFAREA *)NULL,blk+fmapblk);
619 copy(bp1->b_un.b_buf,bp2->b_un.b_buf,BSIZE);
620 dirty(bp2);
621 }
622 }
623 badblk = dupblk = 0;
624 freeblk.df_nfree = superblk.s_nfree;
625 for(n = 0; n < NICFREE; n++)
626 freeblk.df_free[n] = superblk.s_free[n];
627 freechk();
628 if(badblk) {
629 pfatal("%d BAD BLKS IN FREE LIST",badblk);
630 printf("\n");
631 }
632 if(dupblk)
633 pwarn("%d DUP BLKS IN FREE LIST\n",dupblk);
634 if(fixfree == 0) {
635 if((n_blks+n_free) != (fmax-fmin)) {
636 pwarn("%ld BLK(S) MISSING\n",
637 fmax-fmin-n_blks-n_free);
638 fixfree = 1;
639 }
640 else if(n_free != superblk.s_tfree) {
641 pwarn("FREE BLK COUNT WRONG IN SUPERBLK");
642 if (preen)
643 printf(" (FIXED)\n");
644 if(preen || reply("FIX") == YES) {
645 superblk.s_tfree = n_free;
646 sbdirty();
647 }
648 }
649 }
650 if(fixfree) {
651 pwarn("BAD FREE LIST");
652 if (preen)
653 printf(" (SALVAGED)\n");
654 else if(reply("SALVAGE") == NO)
655 fixfree = 0;
656 }
657 }
658
659
660 if(fixfree) {
661 if (preen == 0)
662 printf("** Phase 6 - Salvage Free List\n");
663 makefree();
664 n_free = superblk.s_tfree;
665 }
666
667
668 pwarn("%ld files %ld blocks %ld free\n", n_files,n_blks,n_free);
669 if(dfile.mod) {
670 time(&superblk.s_time);
671 sbdirty();
672 }
673 ckfini();
674 sync();
675 if(dfile.mod && hotroot) {
676 printf("\n***** BOOT UNIX (NO SYNC!) *****\n");
677 exit(4);
678 }
679 if(dfile.mod && preen == 0)
680 printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
681}
682
683/* VARARGS1 */
684error(s1,s2,s3,s4)
685char *s1;
686{
687 printf(s1,s2,s3,s4);
688}
689
690/* VARARGS1 */
691errexit(s1,s2,s3,s4)
692char *s1;
693{
694 error(s1,s2,s3,s4);
695 exit(8);
696}
697
698/*
699 * Pfatal is called when an inconsistency occurs
700 * which should not happen during normal operations.
701 * It prints a message and then dies.
702 * When not preening, this is just a printf.
703 */
704pfatal(s,a1,a2,a3)
705{
706
707 if (preen) {
708 printf("%s: ", devname);
709 printf(s, a1, a2, a3);
710 printf("\n");
711 preendie();
712 }
713 printf(s, a1, a2, a3);
714}
715
716/*
717 * Fatal is called to terminate preening
718 * due to unexplainable inconsistency.
719 */
720preendie()
721{
722
723 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
724 exit(8);
725}
726
727/*
728 * Pwarn is like printf when not preening,
729 * or a warning (preceded by filename) when preening.
730 */
731pwarn(s,a1,a2,a3)
732{
733
734 if (preen)
735 printf("%s: ", devname);
736 printf(s, a1, a2, a3);
737}
738
739ckinode(dp,flg)
740DINODE *dp;
741register flg;
742{
743 register daddr_t *ap;
744 register ret;
745 int (*func)(), n;
746 daddr_t iaddrs[NADDR];
747
748 if(SPECIAL)
749 return(KEEPON);
750 l3tol(iaddrs,dp->di_addr,NADDR);
751 func = (flg == ADDR) ? pfunc : dirscan;
752 for(ap = iaddrs; ap < &iaddrs[NADDR-3]; ap++) {
753 if(*ap && (ret = (*func)(*ap)) & STOP)
754 return(ret);
755 }
756 for(n = 1; n < 4; n++) {
757 if(*ap && (ret = iblock(*ap,n,flg)) & STOP)
758 return(ret);
759 ap++;
760 }
761 return(KEEPON);
762}
763
764
765iblock(blk,ilevel,flg)
766daddr_t blk;
767register ilevel;
768{
769 register daddr_t *ap;
770 register n;
771 int (*func)();
772 BUFAREA ib;
773
774 if(flg == ADDR) {
775 func = pfunc;
776 if(((n = (*func)(blk)) & KEEPON) == 0)
777 return(n);
778 }
779 else
780 func = dirscan;
781 if(outrange(blk)) /* protect thyself */
782 return(SKIP);
783 initbarea(&ib);
784 if(getblk(&ib,blk) == NULL)
785 return(SKIP);
786 ilevel--;
787 for(ap = ib.b_un.b_indir; ap < &ib.b_un.b_indir[NINDIR]; ap++) {
788 if(*ap) {
789 if(ilevel > 0) {
790 n = iblock(*ap,ilevel,flg);
791 }
792 else
793 n = (*func)(*ap);
794 if(n & STOP)
795 return(n);
796 }
797 }
798 return(KEEPON);
799}
800
801
802pass1(blk)
803daddr_t blk;
804{
805 register daddr_t *dlp;
806
807 if(outrange(blk)) {
808 blkerr("BAD",blk);
809 if(++badblk >= MAXBAD) {
810 printf("EXCESSIVE BAD BLKS I=%u",inum);
811 if(reply("CONTINUE") == NO)
812 errexit("");
813 return(STOP);
814 }
815 return(SKIP);
816 }
817 if(getbmap(blk)) {
818 blkerr("DUP",blk);
819 if(++dupblk >= MAXDUP) {
820 printf("EXCESSIVE DUP BLKS I=%u",inum);
821 if(reply("CONTINUE") == NO)
822 errexit("");
823 return(STOP);
824 }
825 if(enddup >= &duplist[DUPTBLSIZE]) {
826 printf("DUP TABLE OVERFLOW.");
827 if(reply("CONTINUE") == NO)
828 errexit("");
829 return(STOP);
830 }
831 for(dlp = duplist; dlp < muldup; dlp++) {
832 if(*dlp == blk) {
833 *enddup++ = blk;
834 break;
835 }
836 }
837 if(dlp >= muldup) {
838 *enddup++ = *muldup;
839 *muldup++ = blk;
840 }
841 }
842 else {
843 n_blks++;
844 setbmap(blk);
845 }
846 filsize++;
847 return(KEEPON);
848}
849
850
851pass1b(blk)
852daddr_t blk;
853{
854 register daddr_t *dlp;
855
856 if(outrange(blk))
857 return(SKIP);
858 for(dlp = duplist; dlp < muldup; dlp++) {
859 if(*dlp == blk) {
860 blkerr("DUP",blk);
861 *dlp = *--muldup;
862 *muldup = blk;
863 return(muldup == duplist ? STOP : KEEPON);
864 }
865 }
866 return(KEEPON);
867}
868
869
870pass2(dirp)
871register DIRECT *dirp;
872{
873 register char *p;
874 register n;
875 DINODE *dp;
876
877 if((inum = dirp->d_ino) == 0)
878 return(KEEPON);
879 thisname = pathp;
880 for(p = dirp->d_name; p < &dirp->d_name[DIRSIZ]; )
881 if((*pathp++ = *p++) == 0) {
882 --pathp;
883 break;
884 }
885 *pathp = 0;
886 n = NO;
887 if(inum > imax || inum < ROOTINO)
888 n = direrr("I OUT OF RANGE");
889 else {
890 again:
891 switch(getstate()) {
892 case USTATE:
893 n = direrr("UNALLOCATED");
894 break;
895 case CLEAR:
896 if((n = direrr("DUP/BAD")) == YES)
897 break;
898 if((dp = ginode()) == NULL)
899 break;
900 setstate(DIR ? DSTATE : FSTATE);
901 goto again;
902 case FSTATE:
903 declncnt();
904 break;
905 case DSTATE:
906 declncnt();
907 descend();
908 }
909 }
910 pathp = thisname;
911 if(n == NO)
912 return(KEEPON);
913 dirp->d_ino = 0;
914 return(KEEPON|ALTERD);
915}
916
917
918pass4(blk)
919daddr_t blk;
920{
921 register daddr_t *dlp;
922
923 if(outrange(blk))
924 return(SKIP);
925 if(getbmap(blk)) {
926 for(dlp = duplist; dlp < enddup; dlp++)
927 if(*dlp == blk) {
928 *dlp = *--enddup;
929 return(KEEPON);
930 }
931 clrbmap(blk);
932 n_blks--;
933 }
934 return(KEEPON);
935}
936
937
938pass5(blk)
939daddr_t blk;
940{
941 if(outrange(blk)) {
942 fixfree = 1;
943 if (preen)
944 pfatal("BAD BLOCKS IN FREE LIST.");
945 if(++badblk >= MAXBAD) {
946 printf("EXCESSIVE BAD BLKS IN FREE LIST.");
947 if(reply("CONTINUE") == NO)
948 errexit("");
949 return(STOP);
950 }
951 return(SKIP);
952 }
953 if(getfmap(blk)) {
954 fixfree = 1;
955 if(++dupblk >= DUPTBLSIZE) {
956 printf("EXCESSIVE DUP BLKS IN FREE LIST.");
957 if(reply("CONTINUE") == NO)
958 errexit("");
959 return(STOP);
960 }
961 }
962 else {
963 n_free++;
964 setfmap(blk);
965 }
966 return(KEEPON);
967}
968
969
970blkerr(s,blk)
971daddr_t blk;
972char *s;
973{
974 pfatal("%ld %s I=%u",blk,s,inum);
975 printf("\n");
976 setstate(CLEAR); /* mark for possible clearing */
977}
978
979
980descend()
981{
982 register DINODE *dp;
983 register char *savname;
984 off_t savsize;
985
986 setstate(FSTATE);
987 if((dp = ginode()) == NULL)
988 return;
989 savname = thisname;
990 *pathp++ = '/';
991 savsize = filsize;
992 filsize = dp->di_size;
993 ckinode(dp,DATA);
994 thisname = savname;
995 *--pathp = 0;
996 filsize = savsize;
997}
998
999
1000dirscan(blk)
1001daddr_t blk;
1002{
1003 register DIRECT *dirp;
1004 register char *p1, *p2;
1005 register n;
1006 DIRECT direntry;
1007
1008 if(outrange(blk)) {
1009 filsize -= BSIZE;
1010 return(SKIP);
1011 }
1012 for(dirp = dirblk.b_dir; dirp < &dirblk.b_dir[NDIRECT] &&
1013 filsize > 0; dirp++, filsize -= sizeof(DIRECT)) {
1014 if(getblk(&fileblk,blk) == NULL) {
1015 filsize -= (&dirblk.b_dir[NDIRECT]-dirp)*sizeof(DIRECT);
1016 return(SKIP);
1017 }
1018 p1 = &dirp->d_name[DIRSIZ];
1019 p2 = &direntry.d_name[DIRSIZ];
1020 while(p1 > (char *)dirp)
1021 *--p2 = *--p1;
1022 if((n = (*pfunc)(&direntry)) & ALTERD) {
1023 if(getblk(&fileblk,blk) != NULL) {
1024 p1 = &dirp->d_name[DIRSIZ];
1025 p2 = &direntry.d_name[DIRSIZ];
1026 while(p1 > (char *)dirp)
1027 *--p1 = *--p2;
1028 fbdirty();
1029 }
1030 else
1031 n &= ~ALTERD;
1032 }
1033 if(n & STOP)
1034 return(n);
1035 }
1036 return(filsize > 0 ? KEEPON : STOP);
1037}
1038
1039
1040direrr(s)
1041char *s;
1042{
1043 register DINODE *dp;
1044
1045 pwarn("%s ",s);
1046 pinode();
1047 printf("\n");
1048 if((dp = ginode()) != NULL && ftypeok(dp))
1049 pfatal("%s=%s",DIR?"DIR":"FILE",pathname);
1050 else
1051 pfatal("NAME=%s",pathname);
1052 return(reply("REMOVE"));
1053}
1054
1055
1056adjust(lcnt)
1057register short lcnt;
1058{
1059 register DINODE *dp;
1060
1061 if((dp = ginode()) == NULL)
1062 return;
1063 if(dp->di_nlink == lcnt) {
1064 if(linkup() == NO)
1065 clri("UNREF",NO);
1066 }
1067 else {
1068 pwarn("LINK COUNT %s",
1069 (lfdir==inum)?lfname:(DIR?"DIR":"FILE"));
1070 pinode();
1071 printf(" COUNT %d SHOULD BE %d",
1072 dp->di_nlink,dp->di_nlink-lcnt);
1073 if (preen) {
1074 if (lcnt < 0) {
1075 printf("\n");
1076 preendie();
1077 }
1078 printf(" (ADJUSTED)\n");
1079 }
1080 if(preen || reply("ADJUST") == YES) {
1081 dp->di_nlink -= lcnt;
1082 inodirty();
1083 }
1084 }
1085}
1086
1087
1088clri(s,flg)
1089char *s;
1090{
1091 register DINODE *dp;
1092
1093 if((dp = ginode()) == NULL)
1094 return;
1095 if(flg == YES) {
1096 pwarn("%s %s",s,DIR?"DIR":"FILE");
1097 pinode();
1098 }
1099 if(preen || reply("CLEAR") == YES) {
1100 if (preen)
1101 printf(" (CLEARED)\n");
1102 n_files--;
1103 pfunc = pass4;
1104 ckinode(dp,ADDR);
1105 zapino(dp);
1106 inodirty();
1107 }
1108}
1109
1110
1111setup(dev)
1112char *dev;
1113{
1114 register n;
1115 register BUFAREA *bp;
1116 register MEMSIZE msize;
1117 char *mbase;
1118 daddr_t bcnt, nscrblk;
1119 dev_t rootdev;
1120 off_t smapsz, lncntsz, totsz;
1121 struct {
1122 daddr_t tfree;
1123 ino_t tinode;
1124 char fname[6];
1125 char fpack[6];
1126 } ustatarea;
1127 struct stat statarea;
1128
1129 if(stat("/",&statarea) < 0)
1130 errexit("Can't stat root\n");
1131 rootdev = statarea.st_dev;
1132 if(stat(dev,&statarea) < 0) {
1133 error("Can't stat %s\n",dev);
1134 return(NO);
1135 }
1136 rawflg = 0;
1137 if((statarea.st_mode & S_IFMT) == S_IFBLK) {
1138 if(ustat(statarea.st_rdev, (char *)&ustatarea) >= 0) {
1139 hotroot++;
1140 }
1141 }
1142 else if((statarea.st_mode & S_IFMT) == S_IFCHR)
1143 rawflg++;
1144 else {
1145 if (reply("file is not a block or character device; OK") == NO)
1146 return(NO);
1147 }
1148 if(rootdev == statarea.st_rdev)
1149 hotroot++;
1150 if((dfile.rfdes = open(dev,0)) < 0) {
1151 error("Can't open %s\n",dev);
1152 return(NO);
1153 }
1154 if (preen == 0)
1155 printf("\n%s",dev);
1156 if(nflag || (dfile.wfdes = open(dev,1)) < 0) {
1157 dfile.wfdes = -1;
1158 if (preen)
1159 pfatal("NO WRITE ACCESS");
1160 printf(" (NO WRITE)");
1161 }
1162 if (preen == 0)
1163 printf("\n");
1164 fixfree = 0;
1165 dfile.mod = 0;
1166 n_files = n_blks = n_free = 0;
1167 muldup = enddup = &duplist[0];
1168 badlnp = &badlncnt[0];
1169 lfdir = 0;
1170 rplyflag = 0;
1171 initbarea(&sblk);
1172 initbarea(&fileblk);
1173 initbarea(&inoblk);
1174 sfile.wfdes = sfile.rfdes = -1;
1175 rmscr = 0;
1176 if(getblk(&sblk,SUPERB) == NULL) {
1177 ckfini();
1178 return(NO);
1179 }
1180 imax = ((ino_t)superblk.s_isize - (SUPERB+1)) * INOPB;
1181 fmin = (daddr_t)superblk.s_isize; /* first data blk num */
1182 fmax = superblk.s_fsize; /* first invalid blk num */
1183 if(fmin >= fmax ||
1184 (imax/INOPB) != ((ino_t)superblk.s_isize-(SUPERB+1))) {
1185 pfatal("Size check: fsize %ld isize %d",
1186 superblk.s_fsize,superblk.s_isize);
1187 printf("\n");
1188 ckfini();
1189 return(NO);
1190 }
1191 if (preen == 0)
1192 printf("File System: %.6s Volume: %.6s\n\n", superblk.s_fname,
1193 superblk.s_fpack);
1194 bmapsz = roundup(howmany(fmax,BITSPB),sizeof(*lncntp));
1195 smapsz = roundup(howmany((long)(imax+1),STATEPB),sizeof(*lncntp));
1196 lncntsz = (long)(imax+1) * sizeof(*lncntp);
1197 if(bmapsz > smapsz+lncntsz)
1198 smapsz = bmapsz-lncntsz;
1199 totsz = bmapsz+smapsz+lncntsz;
1200 msize = memsize;
1201 mbase = membase;
1202 if(rawflg) {
1203 if(msize < (MEMSIZE)(NINOBLK*BSIZE) + 2*sizeof(BUFAREA))
1204 rawflg = 0;
1205 else {
1206 msize -= (MEMSIZE)NINOBLK*BSIZE;
1207 mbase += (MEMSIZE)NINOBLK*BSIZE;
1208 niblk = NINOBLK;
1209 startib = fmax;
1210 }
1211 }
1212 clear(mbase,msize);
1213 if((off_t)msize < totsz) {
1214 bmapsz = roundup(bmapsz,BSIZE);
1215 smapsz = roundup(smapsz,BSIZE);
1216 lncntsz = roundup(lncntsz,BSIZE);
1217 nscrblk = (bmapsz+smapsz+lncntsz)>>BSHIFT;
1218 if(tflag == 0) {
1219 printf("\nNEED SCRATCH FILE (%ld BLKS)\n",nscrblk);
1220 do {
1221 printf("ENTER FILENAME: ");
1222 if((n = getline(stdin,scrfile,sizeof(scrfile))) == EOF)
1223 errexit("\n");
1224 } while(n == 0);
1225 }
1226 if(stat(scrfile,&statarea) < 0 ||
1227 (statarea.st_mode & S_IFMT) == S_IFREG)
1228 rmscr++;
1229 if((sfile.wfdes = creat(scrfile,0666)) < 0 ||
1230 (sfile.rfdes = open(scrfile,0)) < 0) {
1231 error("Can't create %s\n",scrfile);
1232 ckfini();
1233 return(NO);
1234 }
1235 bp = &((BUFAREA *)mbase)[(msize/sizeof(BUFAREA))];
1236 poolhead = NULL;
1237 while(--bp >= (BUFAREA *)mbase) {
1238 initbarea(bp);
1239 bp->b_next = poolhead;
1240 poolhead = bp;
1241 }
1242 bp = poolhead;
1243 for(bcnt = 0; bcnt < nscrblk; bcnt++) {
1244 bp->b_bno = bcnt;
1245 dirty(bp);
1246 flush(&sfile,bp);
1247 }
1248 blkmap = freemap = statemap = (char *) NULL;
1249 lncntp = (short *) NULL;
1250 smapblk = bmapsz / BSIZE;
1251 lncntblk = smapblk + smapsz / BSIZE;
1252 fmapblk = smapblk;
1253 }
1254 else {
1255 if(rawflg && (off_t)msize > totsz+BSIZE) {
1256 niblk += (unsigned)((off_t)msize-totsz)>>BSHIFT;
1257 if(niblk > MAXRAW)
1258 niblk = MAXRAW;
1259 msize = memsize - (niblk*BSIZE);
1260 mbase = membase + (niblk*BSIZE);
1261 }
1262 poolhead = NULL;
1263 blkmap = mbase;
1264 statemap = &mbase[(MEMSIZE)bmapsz];
1265 freemap = statemap;
1266 lncntp = (short *)&statemap[(MEMSIZE)smapsz];
1267 }
1268 return(YES);
1269}
1270
1271
1272DINODE *
1273ginode()
1274{
1275 register DINODE *dp;
1276 register char *mbase;
1277 daddr_t iblk;
1278
1279 if(inum > imax)
1280 return(NULL);
1281 iblk = itod(inum);
1282 if(rawflg) {
1283 mbase = membase;
1284 if(iblk < startib || iblk >= startib+niblk) {
1285 if(inoblk.b_dirty)
1286 bwrite(&dfile,mbase,startib,(int)niblk*BSIZE);
1287 inoblk.b_dirty = 0;
1288 if(bread(&dfile,mbase,iblk,(int)niblk*BSIZE) == NO) {
1289 startib = fmax;
1290 return(NULL);
1291 }
1292 startib = iblk;
1293 }
1294 dp = (DINODE *)&mbase[(unsigned)((iblk-startib)<<BSHIFT)];
1295 }
1296 else if(getblk(&inoblk,iblk) != NULL)
1297 dp = inoblk.b_un.b_dinode;
1298 else
1299 return(NULL);
1300 return(dp + itoo(inum));
1301}
1302
1303
1304ftypeok(dp)
1305DINODE *dp;
1306{
1307 switch(dp->di_mode & IFMT) {
1308 case IFDIR:
1309 case IFREG:
1310 case IFBLK:
1311 case IFCHR:
1312 case IFMPC:
1313 case IFMPB:
1314 return(YES);
1315 default:
1316 return(NO);
1317 }
1318}
1319
1320
1321reply(s)
1322char *s;
1323{
1324 char line[80];
1325
1326 if (preen)
1327 pfatal("INTERNAL ERROR: GOT TO reply()");
1328 rplyflag = 1;
1329 printf("\n%s? ",s);
1330 if(nflag || csflag || dfile.wfdes < 0) {
1331 printf(" no\n\n");
1332 return(NO);
1333 }
1334 if(yflag) {
1335 printf(" yes\n\n");
1336 return(YES);
1337 }
1338 if(getline(stdin,line,sizeof(line)) == EOF)
1339 errexit("\n");
1340 printf("\n");
1341 if(line[0] == 'y' || line[0] == 'Y')
1342 return(YES);
1343 else
1344 return(NO);
1345}
1346
1347
1348getline(fp,loc,maxlen)
1349FILE *fp;
1350char *loc;
1351{
1352 register n;
1353 register char *p, *lastloc;
1354
1355 p = loc;
1356 lastloc = &p[maxlen-1];
1357 while((n = getc(fp)) != '\n') {
1358 if(n == EOF)
1359 return(EOF);
1360 if(!isspace(n) && p < lastloc)
1361 *p++ = n;
1362 }
1363 *p = 0;
1364 return(p - loc);
1365}
1366
1367
1368stype(p)
1369register char *p;
1370{
1371 if(*p == 0)
1372 return;
1373 if (*(p+1) == 0) {
1374 if (*p == '3') {
1375 cylsize = 200;
1376 stepsize = 5;
1377 return;
1378 }
1379 if (*p == '4') {
1380 cylsize = 418;
1381 stepsize = 9;
1382 return;
1383 }
1384 }
1385 cylsize = atoi(p);
1386 while(*p && *p != ':')
1387 p++;
1388 if(*p)
1389 p++;
1390 stepsize = atoi(p);
1391 if(stepsize <= 0 || stepsize > cylsize ||
1392 cylsize <= 0 || cylsize > MAXCYL) {
1393 error("Invalid -s argument, defaults assumed\n");
1394 cylsize = stepsize = 0;
1395 }
1396}
1397
1398
1399dostate(s,flg)
1400{
1401 register char *p;
1402 register unsigned byte, shift;
1403 BUFAREA *bp;
1404
1405 byte = (inum)/STATEPB;
1406 shift = LSTATE * ((inum)%STATEPB);
1407 if(statemap != NULL) {
1408 bp = NULL;
1409 p = &statemap[byte];
1410 }
1411 else if((bp = getblk((BUFAREA *)NULL,(daddr_t)(smapblk+(byte/BSIZE)))) == NULL)
1412 errexit("Fatal I/O error\n");
1413 else
1414 p = &bp->b_un.b_buf[byte%BSIZE];
1415 switch(flg) {
1416 case 0:
1417 *p &= ~(SMASK<<(shift));
1418 *p |= s<<(shift);
1419 if(bp != NULL)
1420 dirty(bp);
1421 return(s);
1422 case 1:
1423 return((*p>>(shift)) & SMASK);
1424 }
1425 return(USTATE);
1426}
1427
1428
1429domap(blk,flg)
1430daddr_t blk;
1431{
1432 register char *p;
1433 register unsigned n;
1434 register BUFAREA *bp;
1435 off_t byte;
1436
1437 byte = blk >> BITSHIFT;
1438 n = 1<<((unsigned)(blk & BITMASK));
1439 if(flg & 04) {
1440 p = freemap;
1441 blk = fmapblk;
1442 }
1443 else {
1444 p = blkmap;
1445 blk = 0;
1446 }
1447 if(p != NULL) {
1448 bp = NULL;
1449 p += (unsigned)byte;
1450 }
1451 else if((bp = getblk((BUFAREA *)NULL,blk+(byte>>BSHIFT))) == NULL)
1452 errexit("Fatal I/O error\n");
1453 else
1454 p = &bp->b_un.b_buf[(unsigned)(byte&BMASK)];
1455 switch(flg&03) {
1456 case 0:
1457 *p |= n;
1458 break;
1459 case 1:
1460 n &= *p;
1461 bp = NULL;
1462 break;
1463 case 2:
1464 *p &= ~n;
1465 }
1466 if(bp != NULL)
1467 dirty(bp);
1468 return(n);
1469}
1470
1471
1472dolncnt(val,flg)
1473short val;
1474{
1475 register short *sp;
1476 register BUFAREA *bp;
1477
1478 if(lncntp != NULL) {
1479 bp = NULL;
1480 sp = &lncntp[inum];
1481 }
1482 else if((bp = getblk((BUFAREA *)NULL,(daddr_t)(lncntblk+(inum/SPERB)))) == NULL)
1483 errexit("Fatal I/O error\n");
1484 else
1485 sp = &bp->b_un.b_lnks[inum%SPERB];
1486 switch(flg) {
1487 case 0:
1488 *sp = val;
1489 break;
1490 case 1:
1491 bp = NULL;
1492 break;
1493 case 2:
1494 (*sp)--;
1495 }
1496 if(bp != NULL)
1497 dirty(bp);
1498 return(*sp);
1499}
1500
1501
1502BUFAREA *
1503getblk(bp,blk)
1504daddr_t blk;
1505register BUFAREA *bp;
1506{
1507 register struct filecntl *fcp;
1508
1509 if(bp == NULL) {
1510 bp = search(blk);
1511 fcp = &sfile;
1512 }
1513 else
1514 fcp = &dfile;
1515 if(bp->b_bno == blk)
1516 return(bp);
1517 flush(fcp,bp);
1518 if(bread(fcp,bp->b_un.b_buf,blk,BSIZE) != NO) {
1519 bp->b_bno = blk;
1520 return(bp);
1521 }
1522 bp->b_bno = (daddr_t)-1;
1523 return(NULL);
1524}
1525
1526
1527flush(fcp,bp)
1528struct filecntl *fcp;
1529register BUFAREA *bp;
1530{
1531 if(bp->b_dirty) {
1532 bwrite(fcp,bp->b_un.b_buf,bp->b_bno,BSIZE);
1533 }
1534 bp->b_dirty = 0;
1535}
1536
1537
1538rwerr(s,blk)
1539char *s;
1540daddr_t blk;
1541{
1542 if (preen == 0)
1543 printf("\n");
1544 pfatal("CAN NOT %s: BLK %ld",s,blk);
1545 if(reply("CONTINUE") == NO)
1546 errexit("Program terminated\n");
1547}
1548
1549
1550sizechk(dp)
1551register DINODE *dp;
1552{
1553/*
1554 if (maxblk != howmany(dp->di_size, BSIZE))
1555 printf("POSSIBLE FILE SIZE ERROR I=%u (%ld,%ld)\n\n",
1556 inum, maxblk, howmany(dp->di_size,BSIZE));
1557*/
1558 if(DIR && (dp->di_size % sizeof(DIRECT)) != 0) {
1559 pwarn("DIRECTORY MISALIGNED I=%u\n",inum);
1560 if (preen == 0)
1561 printf("\n");
1562 }
1563}
1564
1565
1566ckfini()
1567{
1568 flush(&dfile,&fileblk);
1569 flush(&dfile,&sblk);
1570 flush(&dfile,&inoblk);
1571 close(dfile.rfdes);
1572 close(dfile.wfdes);
1573 close(sfile.rfdes);
1574 close(sfile.wfdes);
1575 if(rmscr) {
1576 unlink(scrfile);
1577 }
1578}
1579
1580
1581pinode()
1582{
1583 register DINODE *dp;
1584 register char *p;
1585 char uidbuf[200];
1586 char *ctime();
1587
1588 printf(" I=%u ",inum);
1589 if((dp = ginode()) == NULL)
1590 return;
1591 printf(" OWNER=");
1592 if(getpw((int)dp->di_uid,uidbuf) == 0) {
1593 for(p = uidbuf; *p != ':'; p++);
1594 *p = 0;
1595 printf("%s ",uidbuf);
1596 }
1597 else {
1598 printf("%d ",dp->di_uid);
1599 }
1600 printf("MODE=%o\n",dp->di_mode);
1601 if (preen)
1602 printf("%s: ", devname);
1603 printf("SIZE=%ld ",dp->di_size);
1604 p = ctime(&dp->di_mtime);
1605 printf("MTIME=%12.12s %4.4s ",p+4,p+20);
1606}
1607
1608
1609copy(fp,tp,size)
1610register char *tp, *fp;
1611MEMSIZE size;
1612{
1613 while(size--)
1614 *tp++ = *fp++;
1615}
1616
1617
1618freechk()
1619{
1620 register daddr_t *ap;
1621
1622 if(freeblk.df_nfree == 0)
1623 return;
1624 do {
1625 if(freeblk.df_nfree <= 0 || freeblk.df_nfree > NICFREE) {
1626 pfatal("BAD FREEBLK COUNT");
1627 printf("\n");
1628 fixfree = 1;
1629 return;
1630 }
1631 ap = &freeblk.df_free[freeblk.df_nfree];
1632 while(--ap > &freeblk.df_free[0]) {
1633 if(pass5(*ap) == STOP)
1634 return;
1635 }
1636 if(*ap == (daddr_t)0 || pass5(*ap) != KEEPON)
1637 return;
1638 } while(getblk(&fileblk,*ap) != NULL);
1639}
1640
1641
1642makefree()
1643{
1644 register i, cyl, step;
1645 int j;
1646 char flg[MAXCYL];
1647 short addr[MAXCYL];
1648 daddr_t blk, baseblk;
1649
1650 superblk.s_nfree = 0;
1651 superblk.s_flock = 0;
1652 superblk.s_fmod = 0;
1653 superblk.s_tfree = 0;
1654 superblk.s_ninode = 0;
1655 superblk.s_ilock = 0;
1656 superblk.s_ronly = 0;
1657 if(cylsize == 0 || stepsize == 0) {
1658 step = superblk.s_dinfo[0];
1659 cyl = superblk.s_dinfo[1];
1660 }
1661 else {
1662 step = stepsize;
1663 cyl = cylsize;
1664 }
1665 if(step > cyl || step <= 0 || cyl <= 0 || cyl > MAXCYL) {
1666 error("Default free list spacing assumed\n");
1667 step = STEPSIZE;
1668 cyl = CYLSIZE;
1669 }
1670 superblk.s_dinfo[0] = step;
1671 superblk.s_dinfo[1] = cyl;
1672 clear(flg,sizeof(flg));
1673 i = 0;
1674 for(j = 0; j < cyl; j++) {
1675 while(flg[i])
1676 i = (i + 1) % cyl;
1677 addr[j] = i + 1;
1678 flg[i]++;
1679 i = (i + step) % cyl;
1680 }
1681 baseblk = (daddr_t)roundup(fmax,cyl);
1682 clear((char *)&freeblk,BSIZE);
1683 freeblk.df_nfree++;
1684 for( ; baseblk > 0; baseblk -= cyl)
1685 for(i = 0; i < cyl; i++) {
1686 blk = baseblk - addr[i];
1687 if(!outrange(blk) && !getbmap(blk)) {
1688 superblk.s_tfree++;
1689 if(freeblk.df_nfree >= NICFREE) {
1690 fbdirty();
1691 fileblk.b_bno = blk;
1692 flush(&dfile,&fileblk);
1693 clear((char *)&freeblk,BSIZE);
1694 }
1695 freeblk.df_free[freeblk.df_nfree] = blk;
1696 freeblk.df_nfree++;
1697 }
1698 }
1699 superblk.s_nfree = freeblk.df_nfree;
1700 for(i = 0; i < NICFREE; i++)
1701 superblk.s_free[i] = freeblk.df_free[i];
1702 sbdirty();
1703}
1704
1705
1706clear(p,cnt)
1707register char *p;
1708MEMSIZE cnt;
1709{
1710 while(cnt--)
1711 *p++ = 0;
1712}
1713
1714
1715BUFAREA *
1716search(blk)
1717daddr_t blk;
1718{
1719 register BUFAREA *pbp, *bp;
1720
1721 for(bp = (BUFAREA *) &poolhead; bp->b_next; ) {
1722 pbp = bp;
1723 bp = pbp->b_next;
1724 if(bp->b_bno == blk)
1725 break;
1726 }
1727 pbp->b_next = bp->b_next;
1728 bp->b_next = poolhead;
1729 poolhead = bp;
1730 return(bp);
1731}
1732
1733
1734findino(dirp)
1735register DIRECT *dirp;
1736{
1737 register char *p1, *p2;
1738
1739 if(dirp->d_ino == 0)
1740 return(KEEPON);
1741 for(p1 = dirp->d_name,p2 = srchname;*p2++ == *p1; p1++) {
1742 if(*p1 == 0 || p1 == &dirp->d_name[DIRSIZ-1]) {
1743 if(dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
1744 parentdir = dirp->d_ino;
1745 return(STOP);
1746 }
1747 }
1748 return(KEEPON);
1749}
1750
1751
1752mkentry(dirp)
1753register DIRECT *dirp;
1754{
1755 register ino_t in;
1756 register char *p;
1757
1758 if(dirp->d_ino)
1759 return(KEEPON);
1760 dirp->d_ino = orphan;
1761 in = orphan;
1762 p = &dirp->d_name[8];
1763 *--p = 0;
1764 while(p > dirp->d_name) {
1765 *--p = (in % 10) + '0';
1766 in /= 10;
1767 }
1768 *p = '#';
1769 return(ALTERD|STOP);
1770}
1771
1772
1773chgdd(dirp)
1774register 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
1784
1785linkup()
1786{
1787 register DINODE *dp;
1788 register lostdir;
1789 register ino_t pdir;
1790
1791 if((dp = ginode()) == NULL)
1792 return(NO);
1793 lostdir = DIR;
1794 pdir = parentdir;
1795 pwarn("UNREF %s ",lostdir ? "DIR" : "FILE");
1796 pinode();
1797 if (preen && dp->di_size == 0)
1798 return(NO);
1799 if (preen)
1800 printf(" (RECONNECTED)\n");
1801 else
1802 if (reply("RECONNECT") == NO)
1803 return(NO);
1804 orphan = inum;
1805 if(lfdir == 0) {
1806 inum = ROOTINO;
1807 if((dp = ginode()) == NULL) {
1808 inum = orphan;
1809 return(NO);
1810 }
1811 pfunc = findino;
1812 srchname = lfname;
1813 filsize = dp->di_size;
1814 parentdir = 0;
1815 ckinode(dp,DATA);
1816 inum = orphan;
1817 if((lfdir = parentdir) == 0) {
1818 pfatal("SORRY. NO lost+found DIRECTORY");
1819 printf("\n\n");
1820 return(NO);
1821 }
1822 }
1823 inum = lfdir;
1824 if((dp = ginode()) == NULL || !DIR || getstate() != FSTATE) {
1825 inum = orphan;
1826 pfatal("SORRY. NO lost+found DIRECTORY");
1827 printf("\n\n");
1828 return(NO);
1829 }
1830 if(dp->di_size & BMASK) {
1831 dp->di_size = roundup(dp->di_size,BSIZE);
1832 inodirty();
1833 }
1834 filsize = dp->di_size;
1835 inum = orphan;
1836 pfunc = mkentry;
1837 if((ckinode(dp,DATA) & ALTERD) == 0) {
1838 pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
1839 printf("\n\n");
1840 return(NO);
1841 }
1842 declncnt();
1843 if(lostdir) {
1844 pfunc = chgdd;
1845 dp = ginode();
1846 filsize = dp->di_size;
1847 ckinode(dp,DATA);
1848 inum = lfdir;
1849 if((dp = ginode()) != NULL) {
1850 dp->di_nlink++;
1851 inodirty();
1852 setlncnt(getlncnt()+1);
1853 }
1854 inum = orphan;
1855 pwarn("DIR I=%u CONNECTED. ",orphan);
1856 printf("PARENT WAS I=%u\n",pdir);
1857 if (preen == 0)
1858 printf("\n");
1859 }
1860 return(YES);
1861}
1862
1863
1864bread(fcp,buf,blk,size)
1865daddr_t blk;
1866register struct filecntl *fcp;
1867register size;
1868char *buf;
1869{
1870 if(lseek(fcp->rfdes,blk<<BSHIFT,0) < 0)
1871 rwerr("SEEK",blk);
1872 else if(read(fcp->rfdes,buf,size) == size)
1873 return(YES);
1874 rwerr("READ",blk);
1875 return(NO);
1876}
1877
1878
1879bwrite(fcp,buf,blk,size)
1880daddr_t blk;
1881register struct filecntl *fcp;
1882register size;
1883char *buf;
1884{
1885 if(fcp->wfdes < 0)
1886 return(NO);
1887 if(lseek(fcp->wfdes,blk<<BSHIFT,0) < 0)
1888 rwerr("SEEK",blk);
1889 else if(write(fcp->wfdes,buf,size) == size) {
1890 fcp->mod = 1;
1891 return(YES);
1892 }
1893 rwerr("WRITE",blk);
1894 return(NO);
1895}
1896
1897catch()
1898{
1899 ckfini();
1900 exit(12);
1901}
1902
1903ustat(x, s)
1904char *s;
1905{
1906 return(-1);
1907}