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