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