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