|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char sccsid[] = "@(#)utilities.c 5.13 (Berkeley) 6/7/88";
9: #endif not lint
10:
11: #include <stdio.h>
12: #include <ctype.h>
13: #include <sys/param.h>
14: #include <sys/inode.h>
15: #include <sys/fs.h>
16: #include <sys/dir.h>
17: #include "fsck.h"
18:
19: long diskreads, totalreads; /* Disk cache statistics */
20: long lseek();
21:
22: ftypeok(dp)
23: DINODE *dp;
24: {
25: switch (dp->di_mode & IFMT) {
26:
27: case IFDIR:
28: case IFREG:
29: case IFBLK:
30: case IFCHR:
31: case IFLNK:
32: case IFSOCK:
33: return (1);
34:
35: default:
36: if (debug)
37: printf("bad file type 0%o\n", dp->di_mode);
38: return (0);
39: }
40: }
41:
42: reply(s)
43: char *s;
44: {
45: char line[80];
46: int cont = (strcmp(s, "CONTINUE") == 0);
47:
48: if (preen)
49: pfatal("INTERNAL ERROR: GOT TO reply()");
50: printf("\n%s? ", s);
51: if (!cont && (nflag || dfile.wfdes < 0)) {
52: printf(" no\n\n");
53: return (0);
54: }
55: if (yflag || (cont && nflag)) {
56: printf(" yes\n\n");
57: return (1);
58: }
59: if (getline(stdin, line, sizeof(line)) == EOF)
60: errexit("\n");
61: printf("\n");
62: if (line[0] == 'y' || line[0] == 'Y')
63: return (1);
64: else
65: return (0);
66: }
67:
68: getline(fp, loc, maxlen)
69: FILE *fp;
70: char *loc;
71: {
72: register n;
73: register char *p, *lastloc;
74:
75: p = loc;
76: lastloc = &p[maxlen-1];
77: while ((n = getc(fp)) != '\n') {
78: if (n == EOF)
79: return (EOF);
80: if (!isspace(n) && p < lastloc)
81: *p++ = n;
82: }
83: *p = 0;
84: return (p - loc);
85: }
86:
87: /*
88: * Malloc buffers and set up cache.
89: */
90: bufinit()
91: {
92: register BUFAREA *bp;
93: long bufcnt, i;
94: char *bufp;
95:
96: bufp = (char *)malloc(sblock.fs_bsize);
97: if (bufp == 0)
98: errexit("cannot allocate buffer pool\n");
99: cgblk.b_un.b_buf = bufp;
100: initbarea(&cgblk);
101: bufhead.b_next = bufhead.b_prev = &bufhead;
102: bufcnt = MAXBUFSPACE / sblock.fs_bsize;
103: if (bufcnt < MINBUFS)
104: bufcnt = MINBUFS;
105: for (i = 0; i < bufcnt; i++) {
106: bp = (BUFAREA *)malloc(sizeof(BUFAREA));
107: bufp = (char *)malloc(sblock.fs_bsize);
108: if (bp == 0 || bufp == 0) {
109: if (i >= MINBUFS)
110: break;
111: errexit("cannot allocate buffer pool\n");
112: }
113: bp->b_un.b_buf = bufp;
114: bp->b_prev = &bufhead;
115: bp->b_next = bufhead.b_next;
116: bufhead.b_next->b_prev = bp;
117: bufhead.b_next = bp;
118: initbarea(bp);
119: }
120: bufhead.b_size = i; /* save number of buffers */
121: }
122:
123: /*
124: * Manage a cache of directory blocks.
125: */
126: BUFAREA *
127: getdatablk(blkno, size)
128: daddr_t blkno;
129: long size;
130: {
131: register BUFAREA *bp;
132:
133: for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
134: if (bp->b_bno == fsbtodb(&sblock, blkno))
135: goto foundit;
136: for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
137: if ((bp->b_flags & B_INUSE) == 0)
138: break;
139: if (bp == &bufhead)
140: errexit("deadlocked buffer pool\n");
141: getblk(bp, blkno, size);
142: /* fall through */
143: foundit:
144: totalreads++;
145: bp->b_prev->b_next = bp->b_next;
146: bp->b_next->b_prev = bp->b_prev;
147: bp->b_prev = &bufhead;
148: bp->b_next = bufhead.b_next;
149: bufhead.b_next->b_prev = bp;
150: bufhead.b_next = bp;
151: bp->b_flags |= B_INUSE;
152: return (bp);
153: }
154:
155: BUFAREA *
156: getblk(bp, blk, size)
157: register BUFAREA *bp;
158: daddr_t blk;
159: long size;
160: {
161: register struct filecntl *fcp;
162: daddr_t dblk;
163:
164: fcp = &dfile;
165: dblk = fsbtodb(&sblock, blk);
166: if (bp->b_bno == dblk)
167: return (bp);
168: flush(fcp, bp);
169: diskreads++;
170: bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size);
171: bp->b_bno = dblk;
172: bp->b_size = size;
173: return (bp);
174: }
175:
176: flush(fcp, bp)
177: struct filecntl *fcp;
178: register BUFAREA *bp;
179: {
180: register int i, j;
181:
182: if (!bp->b_dirty)
183: return;
184: if (bp->b_errs != 0)
185: pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
186: (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
187: bp->b_bno);
188: bp->b_dirty = 0;
189: bp->b_errs = 0;
190: bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
191: if (bp != &sblk)
192: return;
193: for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
194: bwrite(&dfile, (char *)sblock.fs_csp[j],
195: fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
196: sblock.fs_cssize - i < sblock.fs_bsize ?
197: sblock.fs_cssize - i : sblock.fs_bsize);
198: }
199: }
200:
201: rwerr(s, blk)
202: char *s;
203: daddr_t blk;
204: {
205:
206: if (preen == 0)
207: printf("\n");
208: pfatal("CANNOT %s: BLK %ld", s, blk);
209: if (reply("CONTINUE") == 0)
210: errexit("Program terminated\n");
211: }
212:
213: ckfini()
214: {
215: register BUFAREA *bp;
216: int cnt = 0;
217:
218: flush(&dfile, &sblk);
219: if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
220: !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
221: sblk.b_bno = SBOFF / dev_bsize;
222: sbdirty();
223: flush(&dfile, &sblk);
224: }
225: flush(&dfile, &cgblk);
226: for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) {
227: cnt++;
228: flush(&dfile, bp);
229: }
230: if (bufhead.b_size != cnt)
231: errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
232: if (debug)
233: printf("cache missed %d of %d (%d%%)\n", diskreads,
234: totalreads, diskreads * 100 / totalreads);
235: (void)close(dfile.rfdes);
236: (void)close(dfile.wfdes);
237: }
238:
239: bread(fcp, buf, blk, size)
240: register struct filecntl *fcp;
241: char *buf;
242: daddr_t blk;
243: long size;
244: {
245: char *cp;
246: int i, errs;
247:
248: if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0)
249: rwerr("SEEK", blk);
250: else if (read(fcp->rfdes, buf, (int)size) == size)
251: return (0);
252: rwerr("READ", blk);
253: if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0)
254: rwerr("SEEK", blk);
255: errs = 0;
256: bzero(buf, size);
257: printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
258: for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
259: if (read(fcp->rfdes, cp, secsize) < 0) {
260: lseek(fcp->rfdes, blk * dev_bsize + i + secsize, 0);
261: if (secsize != dev_bsize && dev_bsize != 1)
262: printf(" %d (%d),",
263: (blk * dev_bsize + i) / secsize,
264: blk + i / dev_bsize);
265: else
266: printf(" %d,", blk + i / dev_bsize);
267: errs++;
268: }
269: }
270: printf("\n");
271: return (errs);
272: }
273:
274: bwrite(fcp, buf, blk, size)
275: register struct filecntl *fcp;
276: char *buf;
277: daddr_t blk;
278: long size;
279: {
280: int i;
281: char *cp;
282:
283: if (fcp->wfdes < 0)
284: return;
285: if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0)
286: rwerr("SEEK", blk);
287: else if (write(fcp->wfdes, buf, (int)size) == size) {
288: fcp->mod = 1;
289: return;
290: }
291: rwerr("WRITE", blk);
292: if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0)
293: rwerr("SEEK", blk);
294: printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
295: for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
296: if (write(fcp->wfdes, cp, dev_bsize) < 0) {
297: lseek(fcp->rfdes, blk * dev_bsize + i + dev_bsize, 0);
298: printf(" %d,", blk + i / dev_bsize);
299: }
300: printf("\n");
301: return;
302: }
303:
304: /*
305: * allocate a data block with the specified number of fragments
306: */
307: allocblk(frags)
308: int frags;
309: {
310: register int i, j, k;
311:
312: if (frags <= 0 || frags > sblock.fs_frag)
313: return (0);
314: for (i = 0; i < fmax - sblock.fs_frag; i += sblock.fs_frag) {
315: for (j = 0; j <= sblock.fs_frag - frags; j++) {
316: if (getbmap(i + j))
317: continue;
318: for (k = 1; k < frags; k++)
319: if (getbmap(i + j + k))
320: break;
321: if (k < frags) {
322: j += k;
323: continue;
324: }
325: for (k = 0; k < frags; k++)
326: setbmap(i + j + k);
327: n_blks += frags;
328: return (i + j);
329: }
330: }
331: return (0);
332: }
333:
334: /*
335: * Free a previously allocated block
336: */
337: freeblk(blkno, frags)
338: daddr_t blkno;
339: int frags;
340: {
341: struct inodesc idesc;
342:
343: idesc.id_blkno = blkno;
344: idesc.id_numfrags = frags;
345: pass4check(&idesc);
346: }
347:
348: /*
349: * Find a pathname
350: */
351: getpathname(namebuf, curdir, ino)
352: char *namebuf;
353: ino_t curdir, ino;
354: {
355: int len;
356: register char *cp;
357: struct inodesc idesc;
358: extern int findname();
359:
360: if (statemap[ino] != DSTATE && statemap[ino] != DFOUND) {
361: strcpy(namebuf, "?");
362: return;
363: }
364: bzero(&idesc, sizeof(struct inodesc));
365: idesc.id_type = DATA;
366: cp = &namebuf[BUFSIZ - 1];
367: *cp = '\0';
368: if (curdir != ino) {
369: idesc.id_parent = curdir;
370: goto namelookup;
371: }
372: while (ino != ROOTINO) {
373: idesc.id_number = ino;
374: idesc.id_func = findino;
375: idesc.id_name = "..";
376: if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
377: break;
378: namelookup:
379: idesc.id_number = idesc.id_parent;
380: idesc.id_parent = ino;
381: idesc.id_func = findname;
382: idesc.id_name = namebuf;
383: if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0)
384: break;
385: len = strlen(namebuf);
386: cp -= len;
387: if (cp < &namebuf[MAXNAMLEN])
388: break;
389: bcopy(namebuf, cp, len);
390: *--cp = '/';
391: ino = idesc.id_number;
392: }
393: if (ino != ROOTINO) {
394: strcpy(namebuf, "?");
395: return;
396: }
397: bcopy(cp, namebuf, &namebuf[BUFSIZ] - cp);
398: }
399:
400: catch()
401: {
402:
403: ckfini();
404: exit(12);
405: }
406:
407: /*
408: * When preening, allow a single quit to signal
409: * a special exit after filesystem checks complete
410: * so that reboot sequence may be interrupted.
411: */
412: catchquit()
413: {
414: extern returntosingle;
415:
416: printf("returning to single-user after filesystem check\n");
417: returntosingle = 1;
418: (void)signal(SIGQUIT, SIG_DFL);
419: }
420:
421: /*
422: * Ignore a single quit signal; wait and flush just in case.
423: * Used by child processes in preen.
424: */
425: voidquit()
426: {
427:
428: sleep(1);
429: (void)signal(SIGQUIT, SIG_IGN);
430: (void)signal(SIGQUIT, SIG_DFL);
431: }
432:
433: /*
434: * determine whether an inode should be fixed.
435: */
436: dofix(idesc, msg)
437: register struct inodesc *idesc;
438: char *msg;
439: {
440:
441: switch (idesc->id_fix) {
442:
443: case DONTKNOW:
444: if (idesc->id_type == DATA)
445: direrr(idesc->id_number, msg);
446: else
447: pwarn(msg);
448: if (preen) {
449: printf(" (SALVAGED)\n");
450: idesc->id_fix = FIX;
451: return (ALTERED);
452: }
453: if (reply("SALVAGE") == 0) {
454: idesc->id_fix = NOFIX;
455: return (0);
456: }
457: idesc->id_fix = FIX;
458: return (ALTERED);
459:
460: case FIX:
461: return (ALTERED);
462:
463: case NOFIX:
464: return (0);
465:
466: default:
467: errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
468: }
469: /* NOTREACHED */
470: }
471:
472: /* VARARGS1 */
473: errexit(s1, s2, s3, s4)
474: char *s1;
475: {
476: printf(s1, s2, s3, s4);
477: exit(8);
478: }
479:
480: /*
481: * An inconsistency occured which shouldn't during normal operations.
482: * Die if preening, otherwise just printf.
483: */
484: /* VARARGS1 */
485: pfatal(s, a1, a2, a3)
486: char *s;
487: {
488:
489: if (preen) {
490: printf("%s: ", devname);
491: printf(s, a1, a2, a3);
492: printf("\n");
493: printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
494: devname);
495: exit(8);
496: }
497: printf(s, a1, a2, a3);
498: }
499:
500: /*
501: * Pwarn is like printf when not preening,
502: * or a warning (preceded by filename) when preening.
503: */
504: /* VARARGS1 */
505: pwarn(s, a1, a2, a3, a4, a5, a6)
506: char *s;
507: {
508:
509: if (preen)
510: printf("%s: ", devname);
511: printf(s, a1, a2, a3, a4, a5, a6);
512: }
513:
514: #ifndef lint
515: /*
516: * Stub for routines from kernel.
517: */
518: panic(s)
519: char *s;
520: {
521:
522: pfatal("INTERNAL INCONSISTENCY:");
523: errexit(s);
524: }
525: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.