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