|
|
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; ap < aplim; ap++, i++)
1354: if (*ap) {
1355: idesc->id_blkno = *ap;
1356: if (ilevel > 0)
1357: n = iblock(idesc, ilevel,
1358: isize - i*NINDIR(&sblock)*sblock.fs_bsize);
1359: else
1360: n = (*func)(idesc);
1361: if (n & STOP)
1362: return (n);
1363: }
1364: return (KEEPON);
1365: }
1366:
1367: outrange(blk, cnt)
1368: daddr_t blk;
1369: int cnt;
1370: {
1371: register int c;
1372:
1373: if ((unsigned)(blk+cnt) > fmax)
1374: return (1);
1375: c = dtog(&sblock, blk);
1376: if (blk < cgdmin(&sblock, c)) {
1377: if ((blk+cnt) > cgsblock(&sblock, c)) {
1378: if (debug) {
1379: printf("blk %d < cgdmin %d;",
1380: blk, cgdmin(&sblock, c));
1381: printf(" blk+cnt %d > cgsbase %d\n",
1382: blk+cnt, cgsblock(&sblock, c));
1383: }
1384: return (1);
1385: }
1386: } else {
1387: if ((blk+cnt) > cgbase(&sblock, c+1)) {
1388: if (debug) {
1389: printf("blk %d >= cgdmin %d;",
1390: blk, cgdmin(&sblock, c));
1391: printf(" blk+cnt %d > sblock.fs_fpg %d\n",
1392: blk+cnt, sblock.fs_fpg);
1393: }
1394: return (1);
1395: }
1396: }
1397: return (0);
1398: }
1399:
1400: blkerr(ino, s, blk)
1401: ino_t ino;
1402: char *s;
1403: daddr_t blk;
1404: {
1405:
1406: pfatal("%ld %s I=%u", blk, s, ino);
1407: printf("\n");
1408: statemap[ino] = CLEAR;
1409: }
1410:
1411: descend(parentino, inumber)
1412: struct inodesc *parentino;
1413: ino_t inumber;
1414: {
1415: register DINODE *dp;
1416: struct inodesc curino;
1417:
1418: bzero((char *)&curino, sizeof(struct inodesc));
1419: statemap[inumber] = FSTATE;
1420: if ((dp = ginode(inumber)) == NULL)
1421: return;
1422: if (dp->di_size == 0) {
1423: direrr(inumber, "ZERO LENGTH DIRECTORY");
1424: if (reply("REMOVE") == 1)
1425: statemap[inumber] = CLEAR;
1426: return;
1427: }
1428: if (dp->di_size < MINDIRSIZE) {
1429: direrr(inumber, "DIRECTORY TOO SHORT");
1430: dp->di_size = MINDIRSIZE;
1431: if (reply("FIX") == 1)
1432: inodirty();
1433: }
1434: curino.id_type = DATA;
1435: curino.id_func = parentino->id_func;
1436: curino.id_parent = parentino->id_number;
1437: curino.id_number = inumber;
1438: curino.id_filesize = dp->di_size;
1439: (void)ckinode(dp, &curino);
1440: }
1441:
1442: dirscan(idesc)
1443: register struct inodesc *idesc;
1444: {
1445: register DIRECT *dp;
1446: int dsize, n;
1447: long blksiz;
1448: char dbuf[DIRBLKSIZ];
1449:
1450: if (idesc->id_type != DATA)
1451: errexit("wrong type to dirscan %d\n", idesc->id_type);
1452: blksiz = idesc->id_numfrags * sblock.fs_fsize;
1453: if (outrange(idesc->id_blkno, idesc->id_numfrags)) {
1454: idesc->id_filesize -= blksiz;
1455: return (SKIP);
1456: }
1457: idesc->id_loc = 0;
1458: for (dp = fsck_readdir(idesc); dp != NULL; dp = fsck_readdir(idesc)) {
1459: dsize = dp->d_reclen;
1460: bcopy((char *)dp, dbuf, dsize);
1461: idesc->id_dirp = (DIRECT *)dbuf;
1462: if ((n = (*idesc->id_func)(idesc)) & ALTERED) {
1463: if (getblk(&fileblk, idesc->id_blkno, blksiz) != NULL) {
1464: bcopy(dbuf, (char *)dp, dsize);
1465: dirty(&fileblk);
1466: sbdirty();
1467: } else
1468: n &= ~ALTERED;
1469: }
1470: if (n & STOP)
1471: return (n);
1472: }
1473: return (idesc->id_filesize > 0 ? KEEPON : STOP);
1474: }
1475:
1476: /*
1477: * get next entry in a directory.
1478: */
1479: DIRECT *
1480: fsck_readdir(idesc)
1481: register struct inodesc *idesc;
1482: {
1483: register DIRECT *dp, *ndp;
1484: long size, blksiz;
1485:
1486: blksiz = idesc->id_numfrags * sblock.fs_fsize;
1487: if (getblk(&fileblk, idesc->id_blkno, blksiz) == NULL) {
1488: idesc->id_filesize -= blksiz - idesc->id_loc;
1489: return NULL;
1490: }
1491: if (idesc->id_loc % DIRBLKSIZ == 0 && idesc->id_filesize > 0 &&
1492: idesc->id_loc < blksiz) {
1493: dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
1494: if (dircheck(idesc, dp))
1495: goto dpok;
1496: idesc->id_loc += DIRBLKSIZ;
1497: idesc->id_filesize -= DIRBLKSIZ;
1498: dp->d_reclen = DIRBLKSIZ;
1499: dp->d_ino = 0;
1500: dp->d_namlen = 0;
1501: dp->d_name[0] = '\0';
1502: if (dofix(idesc))
1503: dirty(&fileblk);
1504: return (dp);
1505: }
1506: dpok:
1507: if (idesc->id_filesize <= 0 || idesc->id_loc >= blksiz)
1508: return NULL;
1509: dp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
1510: idesc->id_loc += dp->d_reclen;
1511: idesc->id_filesize -= dp->d_reclen;
1512: ndp = (DIRECT *)(dirblk.b_buf + idesc->id_loc);
1513: if ((idesc->id_filesize <= 0 && idesc->id_loc % DIRBLKSIZ != 0) ||
1514: (idesc->id_loc < blksiz && idesc->id_filesize > 0 &&
1515: dircheck(idesc, ndp) == 0)) {
1516: size = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
1517: dp->d_reclen += size;
1518: idesc->id_loc += size;
1519: idesc->id_filesize -= size;
1520: if (dofix(idesc))
1521: dirty(&fileblk);
1522: }
1523: return (dp);
1524: }
1525:
1526: /*
1527: * Verify that a directory entry is valid.
1528: * This is a superset of the checks made in the kernel.
1529: */
1530: dircheck(idesc, dp)
1531: struct inodesc *idesc;
1532: register DIRECT *dp;
1533: {
1534: register int size;
1535: register char *cp;
1536: int spaceleft;
1537:
1538: size = DIRSIZ(dp);
1539: spaceleft = DIRBLKSIZ - (idesc->id_loc % DIRBLKSIZ);
1540: if (dp->d_ino < imax &&
1541: dp->d_reclen != 0 &&
1542: dp->d_reclen <= spaceleft &&
1543: (dp->d_reclen & 0x3) == 0 &&
1544: dp->d_reclen >= size &&
1545: idesc->id_filesize >= size &&
1546: dp->d_namlen <= MAXNAMLEN) {
1547: if (dp->d_ino == 0)
1548: return (1);
1549: for (cp = dp->d_name, size = 0; size < dp->d_namlen; size++)
1550: if (*cp == 0 || (*cp++ & 0200))
1551: return (0);
1552: if (*cp == 0)
1553: return (1);
1554: }
1555: return (0);
1556: }
1557:
1558: direrr(ino, s)
1559: ino_t ino;
1560: char *s;
1561: {
1562: register DINODE *dp;
1563:
1564: pwarn("%s ", s);
1565: pinode(ino);
1566: printf("\n");
1567: if ((dp = ginode(ino)) != NULL && ftypeok(dp))
1568: pfatal("%s=%s\n", DIRCT?"DIR":"FILE", pathname);
1569: else
1570: pfatal("NAME=%s\n", pathname);
1571: }
1572:
1573: adjust(idesc, lcnt)
1574: register struct inodesc *idesc;
1575: short lcnt;
1576: {
1577: register DINODE *dp;
1578:
1579: if ((dp = ginode(idesc->id_number)) == NULL)
1580: return;
1581: if (dp->di_nlink == lcnt) {
1582: if (linkup(idesc->id_number, (ino_t)0) == 0)
1583: clri(idesc, "UNREF", 0);
1584: }
1585: else {
1586: pwarn("LINK COUNT %s",
1587: (lfdir==idesc->id_number)?lfname:(DIRCT?"DIR":"FILE"));
1588: pinode(idesc->id_number);
1589: printf(" COUNT %d SHOULD BE %d",
1590: dp->di_nlink, dp->di_nlink-lcnt);
1591: if (preen) {
1592: if (lcnt < 0) {
1593: printf("\n");
1594: preendie();
1595: }
1596: printf(" (ADJUSTED)\n");
1597: }
1598: if (preen || reply("ADJUST") == 1) {
1599: dp->di_nlink -= lcnt;
1600: inodirty();
1601: }
1602: }
1603: }
1604:
1605: clri(idesc, s, flg)
1606: register struct inodesc *idesc;
1607: char *s;
1608: int flg;
1609: {
1610: register DINODE *dp;
1611:
1612: if ((dp = ginode(idesc->id_number)) == NULL)
1613: return;
1614: if (flg == 1) {
1615: pwarn("%s %s", s, DIRCT?"DIR":"FILE");
1616: pinode(idesc->id_number);
1617: }
1618: if (preen || reply("CLEAR") == 1) {
1619: if (preen)
1620: printf(" (CLEARED)\n");
1621: n_files--;
1622: (void)ckinode(dp, idesc);
1623: zapino(dp);
1624: statemap[idesc->id_number] = USTATE;
1625: inodirty();
1626: inosumbad++;
1627: }
1628: }
1629:
1630: badsb(s)
1631: char *s;
1632: {
1633:
1634: if (preen)
1635: printf("%s: ", devname);
1636: printf("BAD SUPER BLOCK: %s\n", s);
1637: pwarn("USE -b OPTION TO FSCK TO SPECIFY LOCATION OF AN ALTERNATE\n");
1638: pfatal("SUPER-BLOCK TO SUPPLY NEEDED INFORMATION; SEE fsck(8).\n");
1639: }
1640:
1641: DINODE *
1642: ginode(inumber)
1643: ino_t inumber;
1644: {
1645: daddr_t iblk;
1646: static ino_t startinum = 0; /* blk num of first in raw area */
1647:
1648:
1649: if (inumber < ROOTINO || inumber > imax) {
1650: if (debug && inumber > imax)
1651: printf("inumber out of range (%d)\n", inumber);
1652: return (NULL);
1653: }
1654: if (startinum == 0 ||
1655: inumber < startinum || inumber >= startinum + INOPB(&sblock)) {
1656: iblk = itod(&sblock, inumber);
1657: if (getblk(&inoblk, iblk, sblock.fs_bsize) == NULL) {
1658: return (NULL);
1659: }
1660: startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
1661: }
1662: return (&inoblk.b_un.b_dinode[inumber % INOPB(&sblock)]);
1663: }
1664:
1665: ftypeok(dp)
1666: DINODE *dp;
1667: {
1668: switch (dp->di_mode & IFMT) {
1669:
1670: case IFDIR:
1671: case IFREG:
1672: case IFBLK:
1673: case IFCHR:
1674: case IFLNK:
1675: case IFSOCK:
1676: return (1);
1677:
1678: default:
1679: if (debug)
1680: printf("bad file type 0%o\n", dp->di_mode);
1681: return (0);
1682: }
1683: }
1684:
1685: reply(s)
1686: char *s;
1687: {
1688: char line[80];
1689:
1690: if (preen)
1691: pfatal("INTERNAL ERROR: GOT TO reply()");
1692: rplyflag = 1;
1693: printf("\n%s? ", s);
1694: if (nflag || dfile.wfdes < 0) {
1695: printf(" no\n\n");
1696: return (0);
1697: }
1698: if (yflag) {
1699: printf(" yes\n\n");
1700: return (1);
1701: }
1702: if (getline(stdin, line, sizeof(line)) == EOF)
1703: errexit("\n");
1704: printf("\n");
1705: if (line[0] == 'y' || line[0] == 'Y')
1706: return (1);
1707: else
1708: return (0);
1709: }
1710:
1711: getline(fp, loc, maxlen)
1712: FILE *fp;
1713: char *loc;
1714: {
1715: register n;
1716: register char *p, *lastloc;
1717:
1718: p = loc;
1719: lastloc = &p[maxlen-1];
1720: while ((n = getc(fp)) != '\n') {
1721: if (n == EOF)
1722: return (EOF);
1723: if (!isspace(n) && p < lastloc)
1724: *p++ = n;
1725: }
1726: *p = 0;
1727: return (p - loc);
1728: }
1729:
1730: BUFAREA *
1731: getblk(bp, blk, size)
1732: register BUFAREA *bp;
1733: daddr_t blk;
1734: long size;
1735: {
1736: register struct filecntl *fcp;
1737: daddr_t dblk;
1738:
1739: fcp = &dfile;
1740: dblk = fsbtodb(&sblock, blk);
1741: if (bp->b_bno == dblk)
1742: return (bp);
1743: flush(fcp, bp);
1744: if (bread(fcp, bp->b_un.b_buf, dblk, size) != 0) {
1745: bp->b_bno = dblk;
1746: bp->b_size = size;
1747: return (bp);
1748: }
1749: bp->b_bno = (daddr_t)-1;
1750: return (NULL);
1751: }
1752:
1753: flush(fcp, bp)
1754: struct filecntl *fcp;
1755: register BUFAREA *bp;
1756: {
1757:
1758: if (bp->b_dirty)
1759: (void)bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
1760: bp->b_dirty = 0;
1761: }
1762:
1763: rwerr(s, blk)
1764: char *s;
1765: daddr_t blk;
1766: {
1767:
1768: if (preen == 0)
1769: printf("\n");
1770: pfatal("CANNOT %s: BLK %ld", s, blk);
1771: if (reply("CONTINUE") == 0)
1772: errexit("Program terminated\n");
1773: }
1774:
1775: ckfini()
1776: {
1777:
1778: flush(&dfile, &fileblk);
1779: flush(&dfile, &sblk);
1780: if (sblk.b_bno != SBLOCK) {
1781: sblk.b_bno = SBLOCK;
1782: sbdirty();
1783: flush(&dfile, &sblk);
1784: }
1785: flush(&dfile, &inoblk);
1786: (void)close(dfile.rfdes);
1787: (void)close(dfile.wfdes);
1788: }
1789:
1790: pinode(ino)
1791: ino_t ino;
1792: {
1793: register DINODE *dp;
1794: register char *p;
1795: char uidbuf[BUFSIZ];
1796: char *ctime();
1797:
1798: printf(" I=%u ", ino);
1799: if ((dp = ginode(ino)) == NULL)
1800: return;
1801: printf(" OWNER=");
1802: if (getpw((int)dp->di_uid, uidbuf) == 0) {
1803: for (p = uidbuf; *p != ':'; p++);
1804: *p = 0;
1805: printf("%s ", uidbuf);
1806: }
1807: else {
1808: printf("%d ", dp->di_uid);
1809: }
1810: printf("MODE=%o\n", dp->di_mode);
1811: if (preen)
1812: printf("%s: ", devname);
1813: printf("SIZE=%ld ", dp->di_size);
1814: p = ctime(&dp->di_mtime);
1815: printf("MTIME=%12.12s %4.4s ", p+4, p+20);
1816: }
1817:
1818: makecg()
1819: {
1820: int c, blk;
1821: daddr_t dbase, d, dlower, dupper, dmax;
1822: long i, j, s;
1823: ino_t inumber;
1824: register struct csum *cs;
1825: register DINODE *dp;
1826:
1827: sblock.fs_cstotal.cs_nbfree = 0;
1828: sblock.fs_cstotal.cs_nffree = 0;
1829: sblock.fs_cstotal.cs_nifree = 0;
1830: sblock.fs_cstotal.cs_ndir = 0;
1831: for (c = 0; c < sblock.fs_ncg; c++) {
1832: dbase = cgbase(&sblock, c);
1833: dmax = dbase + sblock.fs_fpg;
1834: if (dmax > sblock.fs_size) {
1835: for ( ; dmax >= sblock.fs_size; dmax--)
1836: clrbit(cgrp.cg_free, dmax - dbase);
1837: dmax++;
1838: }
1839: dlower = cgsblock(&sblock, c) - dbase;
1840: dupper = cgdmin(&sblock, c) - dbase;
1841: cs = &sblock.fs_cs(&sblock, c);
1842: (void)time(&cgrp.cg_time);
1843: cgrp.cg_magic = CG_MAGIC;
1844: cgrp.cg_cgx = c;
1845: if (c == sblock.fs_ncg - 1)
1846: cgrp.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
1847: else
1848: cgrp.cg_ncyl = sblock.fs_cpg;
1849: cgrp.cg_niblk = sblock.fs_ipg;
1850: cgrp.cg_ndblk = dmax - dbase;
1851: cgrp.cg_cs.cs_ndir = 0;
1852: cgrp.cg_cs.cs_nffree = 0;
1853: cgrp.cg_cs.cs_nbfree = 0;
1854: cgrp.cg_cs.cs_nifree = 0;
1855: cgrp.cg_rotor = 0;
1856: cgrp.cg_frotor = 0;
1857: cgrp.cg_irotor = 0;
1858: for (i = 0; i < sblock.fs_frag; i++)
1859: cgrp.cg_frsum[i] = 0;
1860: inumber = sblock.fs_ipg * c;
1861: for (i = 0; i < sblock.fs_ipg; inumber++, i++) {
1862: cgrp.cg_cs.cs_nifree++;
1863: clrbit(cgrp.cg_iused, i);
1864: dp = ginode(inumber);
1865: if (dp == NULL)
1866: continue;
1867: if (ALLOC) {
1868: if (DIRCT)
1869: cgrp.cg_cs.cs_ndir++;
1870: cgrp.cg_cs.cs_nifree--;
1871: setbit(cgrp.cg_iused, i);
1872: continue;
1873: }
1874: }
1875: while (i < MAXIPG) {
1876: clrbit(cgrp.cg_iused, i);
1877: i++;
1878: }
1879: if (c == 0)
1880: for (i = 0; i < ROOTINO; i++) {
1881: setbit(cgrp.cg_iused, i);
1882: cgrp.cg_cs.cs_nifree--;
1883: }
1884: for (s = 0; s < MAXCPG; s++) {
1885: cgrp.cg_btot[s] = 0;
1886: for (i = 0; i < NRPOS; i++)
1887: cgrp.cg_b[s][i] = 0;
1888: }
1889: if (c == 0) {
1890: dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
1891: }
1892: for (d = dlower; d < dupper; d++)
1893: clrbit(cgrp.cg_free, d);
1894: for (d = 0; (d + sblock.fs_frag) <= dmax - dbase;
1895: d += sblock.fs_frag) {
1896: j = 0;
1897: for (i = 0; i < sblock.fs_frag; i++) {
1898: if (!getbmap(dbase + d + i)) {
1899: setbit(cgrp.cg_free, d + i);
1900: j++;
1901: } else
1902: clrbit(cgrp.cg_free, d+i);
1903: }
1904: if (j == sblock.fs_frag) {
1905: cgrp.cg_cs.cs_nbfree++;
1906: cgrp.cg_btot[cbtocylno(&sblock, d)]++;
1907: cgrp.cg_b[cbtocylno(&sblock, d)]
1908: [cbtorpos(&sblock, d)]++;
1909: } else if (j > 0) {
1910: cgrp.cg_cs.cs_nffree += j;
1911: blk = blkmap(&sblock, cgrp.cg_free, d);
1912: fragacct(&sblock, blk, cgrp.cg_frsum, 1);
1913: }
1914: }
1915: for (j = d; d < dmax - dbase; d++) {
1916: if (!getbmap(dbase + d)) {
1917: setbit(cgrp.cg_free, d);
1918: cgrp.cg_cs.cs_nffree++;
1919: } else
1920: clrbit(cgrp.cg_free, d);
1921: }
1922: for (; d % sblock.fs_frag != 0; d++)
1923: clrbit(cgrp.cg_free, d);
1924: if (j != d) {
1925: blk = blkmap(&sblock, cgrp.cg_free, j);
1926: fragacct(&sblock, blk, cgrp.cg_frsum, 1);
1927: }
1928: for (d /= sblock.fs_frag; d < MAXBPG(&sblock); d ++)
1929: clrblock(&sblock, cgrp.cg_free, d);
1930: sblock.fs_cstotal.cs_nffree += cgrp.cg_cs.cs_nffree;
1931: sblock.fs_cstotal.cs_nbfree += cgrp.cg_cs.cs_nbfree;
1932: sblock.fs_cstotal.cs_nifree += cgrp.cg_cs.cs_nifree;
1933: sblock.fs_cstotal.cs_ndir += cgrp.cg_cs.cs_ndir;
1934: *cs = cgrp.cg_cs;
1935: (void)bwrite(&dfile, (char *)&cgrp,
1936: fsbtodb(&sblock, cgtod(&sblock, c)), sblock.fs_cgsize);
1937: }
1938: for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
1939: (void)bwrite(&dfile, (char *)sblock.fs_csp[j],
1940: fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
1941: sblock.fs_cssize - i < sblock.fs_bsize ?
1942: sblock.fs_cssize - i : sblock.fs_bsize);
1943: }
1944: sblock.fs_ronly = 0;
1945: sblock.fs_fmod = 0;
1946: sbdirty();
1947: }
1948:
1949: findino(idesc)
1950: struct inodesc *idesc;
1951: {
1952: register DIRECT *dirp = idesc->id_dirp;
1953:
1954: if (dirp->d_ino == 0)
1955: return (KEEPON);
1956: if (!strcmp(dirp->d_name, srchname)) {
1957: if (dirp->d_ino >= ROOTINO && dirp->d_ino <= imax)
1958: idesc->id_parent = dirp->d_ino;
1959: return (STOP);
1960: }
1961: return (KEEPON);
1962: }
1963:
1964: mkentry(idesc)
1965: struct inodesc *idesc;
1966: {
1967: register DIRECT *dirp = idesc->id_dirp;
1968: DIRECT newent;
1969: int newlen, oldlen;
1970:
1971: newent.d_namlen = 11;
1972: newlen = DIRSIZ(&newent);
1973: if (dirp->d_ino != 0)
1974: oldlen = DIRSIZ(dirp);
1975: else
1976: oldlen = 0;
1977: if (dirp->d_reclen - oldlen < newlen)
1978: return (KEEPON);
1979: newent.d_reclen = dirp->d_reclen - oldlen;
1980: dirp->d_reclen = oldlen;
1981: dirp = (struct direct *)(((char *)dirp) + oldlen);
1982: dirp->d_ino = idesc->id_parent; /* ino to be entered is in id_parent */
1983: dirp->d_reclen = newent.d_reclen;
1984: dirp->d_namlen = lftempname(dirp->d_name, idesc->id_parent);
1985: return (ALTERED|STOP);
1986: }
1987:
1988: chgdd(idesc)
1989: struct inodesc *idesc;
1990: {
1991: register DIRECT *dirp = idesc->id_dirp;
1992:
1993: if (dirp->d_name[0] == '.' && dirp->d_name[1] == '.' &&
1994: dirp->d_name[2] == 0) {
1995: dirp->d_ino = lfdir;
1996: return (ALTERED|STOP);
1997: }
1998: return (KEEPON);
1999: }
2000:
2001: linkup(orphan, pdir)
2002: ino_t orphan;
2003: ino_t pdir;
2004: {
2005: register DINODE *dp;
2006: int lostdir, len;
2007: struct inodesc idesc;
2008:
2009: bzero((char *)&idesc, sizeof(struct inodesc));
2010: if ((dp = ginode(orphan)) == NULL)
2011: return (0);
2012: lostdir = DIRCT;
2013: pwarn("UNREF %s ", lostdir ? "DIR" : "FILE");
2014: pinode(orphan);
2015: if (preen && dp->di_size == 0)
2016: return (0);
2017: if (preen)
2018: printf(" (RECONNECTED)\n");
2019: else
2020: if (reply("RECONNECT") == 0)
2021: return (0);
2022: pathp = pathname;
2023: *pathp++ = '/';
2024: *pathp = '\0';
2025: if (lfdir == 0) {
2026: if ((dp = ginode(ROOTINO)) == NULL)
2027: return (0);
2028: srchname = lfname;
2029: idesc.id_type = DATA;
2030: idesc.id_func = findino;
2031: idesc.id_number = ROOTINO;
2032: idesc.id_filesize = dp->di_size;
2033: (void)ckinode(dp, &idesc);
2034: if ((lfdir = idesc.id_parent) == 0) {
2035: pfatal("SORRY. NO lost+found DIRECTORY");
2036: printf("\n\n");
2037: return (0);
2038: }
2039: }
2040: if ((dp = ginode(lfdir)) == NULL ||
2041: !DIRCT || statemap[lfdir] != FSTATE) {
2042: pfatal("SORRY. NO lost+found DIRECTORY");
2043: printf("\n\n");
2044: return (0);
2045: }
2046: if (fragoff(&sblock, dp->di_size)) {
2047: dp->di_size = fragroundup(&sblock, dp->di_size);
2048: inodirty();
2049: }
2050: len = strlen(lfname);
2051: bcopy(lfname, pathp, len + 1);
2052: pathp += len;
2053: idesc.id_type = DATA;
2054: idesc.id_func = mkentry;
2055: idesc.id_number = lfdir;
2056: idesc.id_filesize = dp->di_size;
2057: idesc.id_parent = orphan; /* this is the inode to enter */
2058: idesc.id_fix = DONTKNOW;
2059: if ((ckinode(dp, &idesc) & ALTERED) == 0) {
2060: pfatal("SORRY. NO SPACE IN lost+found DIRECTORY");
2061: printf("\n\n");
2062: return (0);
2063: }
2064: lncntp[orphan]--;
2065: *pathp++ = '/';
2066: pathp += lftempname(pathp, orphan);
2067: if (lostdir) {
2068: dp = ginode(orphan);
2069: idesc.id_type = DATA;
2070: idesc.id_func = chgdd;
2071: idesc.id_number = orphan;
2072: idesc.id_filesize = dp->di_size;
2073: idesc.id_fix = DONTKNOW;
2074: (void)ckinode(dp, &idesc);
2075: if ((dp = ginode(lfdir)) != NULL) {
2076: dp->di_nlink++;
2077: inodirty();
2078: lncntp[lfdir]++;
2079: }
2080: pwarn("DIR I=%u CONNECTED. ", orphan);
2081: printf("PARENT WAS I=%u\n", pdir);
2082: if (preen == 0)
2083: printf("\n");
2084: }
2085: return (1);
2086: }
2087:
2088: /*
2089: * generate a temporary name for the lost+found directory.
2090: */
2091: lftempname(bufp, ino)
2092: char *bufp;
2093: ino_t ino;
2094: {
2095: register ino_t in;
2096: register char *cp;
2097: int namlen;
2098:
2099: cp = bufp + 2;
2100: for (in = imax; in > 0; in /= 10)
2101: cp++;
2102: *--cp = 0;
2103: namlen = cp - bufp;
2104: in = ino;
2105: while (cp > bufp) {
2106: *--cp = (in % 10) + '0';
2107: in /= 10;
2108: }
2109: *cp = '#';
2110: return (namlen);
2111: }
2112:
2113: bread(fcp, buf, blk, size)
2114: register struct filecntl *fcp;
2115: char *buf;
2116: daddr_t blk;
2117: long size;
2118: {
2119: if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
2120: rwerr("SEEK", blk);
2121: else if (read(fcp->rfdes, buf, (int)size) == size)
2122: return (1);
2123: rwerr("READ", blk);
2124: return (0);
2125: }
2126:
2127: bwrite(fcp, buf, blk, size)
2128: register struct filecntl *fcp;
2129: char *buf;
2130: daddr_t blk;
2131: long size;
2132: {
2133:
2134: if (fcp->wfdes < 0)
2135: return (0);
2136: if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
2137: rwerr("SEEK", blk);
2138: else if (write(fcp->wfdes, buf, (int)size) == size) {
2139: fcp->mod = 1;
2140: return (1);
2141: }
2142: rwerr("WRITE", blk);
2143: return (0);
2144: }
2145:
2146: catch()
2147: {
2148:
2149: ckfini();
2150: exit(12);
2151: }
2152:
2153: char *
2154: unrawname(cp)
2155: char *cp;
2156: {
2157: char *dp = rindex(cp, '/');
2158: struct stat stb;
2159:
2160: if (dp == 0)
2161: return (cp);
2162: if (stat(cp, &stb) < 0)
2163: return (cp);
2164: if ((stb.st_mode&S_IFMT) != S_IFCHR)
2165: return (cp);
2166: if (*(dp+1) != 'r')
2167: return (cp);
2168: (void)strcpy(dp+1, dp+2);
2169: return (cp);
2170: }
2171:
2172: char *
2173: rawname(cp)
2174: char *cp;
2175: {
2176: static char rawbuf[32];
2177: char *dp = rindex(cp, '/');
2178:
2179: if (dp == 0)
2180: return (0);
2181: *dp = 0;
2182: (void)strcpy(rawbuf, cp);
2183: *dp = '/';
2184: (void)strcat(rawbuf, "/r");
2185: (void)strcat(rawbuf, dp+1);
2186: return (rawbuf);
2187: }
2188:
2189: /*
2190: * determine whether an inode should be fixed.
2191: */
2192: dofix(idesc)
2193: register struct inodesc *idesc;
2194: {
2195:
2196: switch (idesc->id_fix) {
2197:
2198: case DONTKNOW:
2199: direrr(idesc->id_number, "DIRECTORY CORRUPTED");
2200: if (reply("SALVAGE") == 0) {
2201: idesc->id_fix = NOFIX;
2202: return (0);
2203: }
2204: idesc->id_fix = FIX;
2205: return (ALTERED);
2206:
2207: case FIX:
2208: return (ALTERED);
2209:
2210: case NOFIX:
2211: return (0);
2212:
2213: default:
2214: errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
2215: }
2216: /* NOTREACHED */
2217: }
2218:
2219: /* VARARGS1 */
2220: error(s1, s2, s3, s4)
2221: char *s1;
2222: {
2223:
2224: printf(s1, s2, s3, s4);
2225: }
2226:
2227: /* VARARGS1 */
2228: errexit(s1, s2, s3, s4)
2229: char *s1;
2230: {
2231: error(s1, s2, s3, s4);
2232: exit(8);
2233: }
2234:
2235: /*
2236: * An inconsistency occured which shouldn't during normal operations.
2237: * Die if preening, otherwise just printf.
2238: */
2239: /* VARARGS1 */
2240: pfatal(s, a1, a2, a3)
2241: char *s;
2242: {
2243:
2244: if (preen) {
2245: printf("%s: ", devname);
2246: printf(s, a1, a2, a3);
2247: printf("\n");
2248: preendie();
2249: }
2250: printf(s, a1, a2, a3);
2251: }
2252:
2253: preendie()
2254: {
2255:
2256: printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n", devname);
2257: exit(8);
2258: }
2259:
2260: /*
2261: * Pwarn is like printf when not preening,
2262: * or a warning (preceded by filename) when preening.
2263: */
2264: /* VARARGS1 */
2265: pwarn(s, a1, a2, a3, a4, a5, a6)
2266: char *s;
2267: {
2268:
2269: if (preen)
2270: printf("%s: ", devname);
2271: printf(s, a1, a2, a3, a4, a5, a6);
2272: }
2273:
2274: #ifndef lint
2275: /*
2276: * Stub for routines from kernel.
2277: */
2278: panic(s)
2279: char *s;
2280: {
2281:
2282: pfatal("INTERNAL INCONSISTENCY: %s\n", s);
2283: exit(12);
2284: }
2285: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.