timeval => timespec
[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
b82067db 9static char sccsid[] = "@(#)utilities.c 5.32 (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
569ec282 208 flush(fswritefd, &sblk);
55f8bbd7 209 if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
6eb81197 210 !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
bc5c7748 211 sblk.b_bno = SBOFF / dev_bsize;
5d9906c0 212 sbdirty();
569ec282 213 flush(fswritefd, &sblk);
5d9906c0 214 }
569ec282 215 flush(fswritefd, &cgblk);
3249f52d
KM
216 free(cgblk.b_un.b_buf);
217 for (bp = bufhead.b_prev; bp != &bufhead; bp = nbp) {
d8f697fc 218 cnt++;
569ec282 219 flush(fswritefd, bp);
3249f52d
KM
220 nbp = bp->b_prev;
221 free(bp->b_un.b_buf);
222 free((char *)bp);
d8f697fc
KM
223 }
224 if (bufhead.b_size != cnt)
225 errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
c0dee198 226 pbp = pdirbp = (struct bufarea *)0;
adc5a10c 227 if (debug)
d72e970b
KM
228 printf("cache missed %ld of %ld (%d%%)\n", diskreads,
229 totalreads, (int)(diskreads * 100 / totalreads));
569ec282
KM
230 (void)close(fsreadfd);
231 (void)close(fswritefd);
5d9906c0
KM
232}
233
569ec282
KM
234bread(fd, buf, blk, size)
235 int fd;
5d9906c0
KM
236 char *buf;
237 daddr_t blk;
238 long size;
239{
49505034
KM
240 char *cp;
241 int i, errs;
242
569ec282
KM
243 if (lseek(fd, blk * dev_bsize, 0) < 0)
244 rwerror("SEEK", blk);
245 else if (read(fd, buf, (int)size) == size)
49505034 246 return (0);
569ec282
KM
247 rwerror("READ", blk);
248 if (lseek(fd, blk * dev_bsize, 0) < 0)
249 rwerror("SEEK", blk);
49505034 250 errs = 0;
d72e970b 251 bzero(buf, (size_t)size);
919c85da
MK
252 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
253 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
57195990 254 if (read(fd, cp, (int)secsize) != secsize) {
d72e970b 255 (void)lseek(fd, blk * dev_bsize + i + secsize, 0);
55f8bbd7 256 if (secsize != dev_bsize && dev_bsize != 1)
d72e970b 257 printf(" %ld (%ld),",
919c85da
MK
258 (blk * dev_bsize + i) / secsize,
259 blk + i / dev_bsize);
260 else
d72e970b 261 printf(" %ld,", blk + i / dev_bsize);
49505034
KM
262 errs++;
263 }
264 }
cee9cbac 265 printf("\n");
49505034 266 return (errs);
5d9906c0
KM
267}
268
569ec282
KM
269bwrite(fd, buf, blk, size)
270 int fd;
5d9906c0
KM
271 char *buf;
272 daddr_t blk;
273 long size;
274{
cee9cbac
KM
275 int i;
276 char *cp;
5d9906c0 277
569ec282 278 if (fd < 0)
cee9cbac 279 return;
569ec282
KM
280 if (lseek(fd, blk * dev_bsize, 0) < 0)
281 rwerror("SEEK", blk);
282 else if (write(fd, buf, (int)size) == size) {
283 fsmodified = 1;
cee9cbac 284 return;
5d9906c0 285 }
569ec282
KM
286 rwerror("WRITE", blk);
287 if (lseek(fd, blk * dev_bsize, 0) < 0)
288 rwerror("SEEK", blk);
919c85da 289 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
6eb81197 290 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
57195990 291 if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
d72e970b
KM
292 (void)lseek(fd, blk * dev_bsize + i + dev_bsize, 0);
293 printf(" %ld,", blk + i / dev_bsize);
6d8dba44 294 }
cee9cbac
KM
295 printf("\n");
296 return;
5d9906c0
KM
297}
298
3e2a23ca
KM
299/*
300 * allocate a data block with the specified number of fragments
301 */
302allocblk(frags)
569ec282 303 long frags;
3e2a23ca
KM
304{
305 register int i, j, k;
306
307 if (frags <= 0 || frags > sblock.fs_frag)
308 return (0);
569ec282 309 for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
3e2a23ca 310 for (j = 0; j <= sblock.fs_frag - frags; j++) {
569ec282 311 if (testbmap(i + j))
3e2a23ca
KM
312 continue;
313 for (k = 1; k < frags; k++)
569ec282 314 if (testbmap(i + j + k))
3e2a23ca
KM
315 break;
316 if (k < frags) {
317 j += k;
318 continue;
319 }
320 for (k = 0; k < frags; k++)
321 setbmap(i + j + k);
322 n_blks += frags;
323 return (i + j);
324 }
325 }
326 return (0);
327}
328
329/*
330 * Free a previously allocated block
331 */
332freeblk(blkno, frags)
333 daddr_t blkno;
569ec282 334 long frags;
3e2a23ca
KM
335{
336 struct inodesc idesc;
337
338 idesc.id_blkno = blkno;
339 idesc.id_numfrags = frags;
d72e970b 340 (void)pass4check(&idesc);
3e2a23ca
KM
341}
342
3ad2f081
KM
343/*
344 * Find a pathname
345 */
346getpathname(namebuf, curdir, ino)
347 char *namebuf;
348 ino_t curdir, ino;
349{
350 int len;
351 register char *cp;
352 struct inodesc idesc;
57195990 353 static int busy = 0;
3ad2f081
KM
354 extern int findname();
355
57195990
KM
356 if (busy ||
357 (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
d72e970b 358 (void)strcpy(namebuf, "?");
3ad2f081
KM
359 return;
360 }
57195990 361 busy = 1;
569ec282 362 bzero((char *)&idesc, sizeof(struct inodesc));
3ad2f081 363 idesc.id_type = DATA;
57195990 364 idesc.id_fix = IGNORE;
45ae1fd3 365 cp = &namebuf[MAXPATHLEN - 1];
315f1422 366 *cp = '\0';
3ad2f081
KM
367 if (curdir != ino) {
368 idesc.id_parent = curdir;
369 goto namelookup;
370 }
371 while (ino != ROOTINO) {
372 idesc.id_number = ino;
373 idesc.id_func = findino;
374 idesc.id_name = "..";
c7153893 375 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
3ad2f081
KM
376 break;
377 namelookup:
378 idesc.id_number = idesc.id_parent;
379 idesc.id_parent = ino;
380 idesc.id_func = findname;
381 idesc.id_name = namebuf;
c7153893 382 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
3ad2f081
KM
383 break;
384 len = strlen(namebuf);
385 cp -= len;
d72e970b 386 bcopy(namebuf, cp, (size_t)len);
3ad2f081 387 *--cp = '/';
d21a5ed2
KM
388 if (cp < &namebuf[MAXNAMLEN])
389 break;
3ad2f081
KM
390 ino = idesc.id_number;
391 }
57195990 392 busy = 0;
d21a5ed2
KM
393 if (ino != ROOTINO)
394 *--cp = '?';
d72e970b 395 bcopy(cp, namebuf, (size_t)(&namebuf[MAXPATHLEN] - cp));
3ad2f081
KM
396}
397
392fe950 398void
5d9906c0
KM
399catch()
400{
5d9906c0
KM
401 ckfini();
402 exit(12);
403}
404
3cfe4689
MK
405/*
406 * When preening, allow a single quit to signal
407 * a special exit after filesystem checks complete
408 * so that reboot sequence may be interrupted.
409 */
392fe950 410void
3cfe4689
MK
411catchquit()
412{
413 extern returntosingle;
414
415 printf("returning to single-user after filesystem check\n");
416 returntosingle = 1;
417 (void)signal(SIGQUIT, SIG_DFL);
418}
419
420/*
421 * Ignore a single quit signal; wait and flush just in case.
422 * Used by child processes in preen.
423 */
392fe950 424void
3cfe4689
MK
425voidquit()
426{
427
428 sleep(1);
429 (void)signal(SIGQUIT, SIG_IGN);
430 (void)signal(SIGQUIT, SIG_DFL);
431}
432
5d9906c0
KM
433/*
434 * determine whether an inode should be fixed.
435 */
7718c0e6 436dofix(idesc, msg)
5d9906c0 437 register struct inodesc *idesc;
7718c0e6 438 char *msg;
5d9906c0
KM
439{
440
441 switch (idesc->id_fix) {
442
443 case DONTKNOW:
7718c0e6 444 if (idesc->id_type == DATA)
569ec282 445 direrror(idesc->id_number, msg);
7718c0e6
KM
446 else
447 pwarn(msg);
448 if (preen) {
449 printf(" (SALVAGED)\n");
450 idesc->id_fix = FIX;
451 return (ALTERED);
452 }
5d9906c0
KM
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:
57195990 464 case IGNORE:
5d9906c0
KM
465 return (0);
466
467 default:
468 errexit("UNKNOWN INODESC FIX MODE %d\n", idesc->id_fix);
469 }
470 /* NOTREACHED */
471}
472
5d9906c0
KM
473/* VARARGS1 */
474errexit(s1, s2, s3, s4)
475 char *s1;
476{
7718c0e6 477 printf(s1, s2, s3, s4);
5d9906c0
KM
478 exit(8);
479}
480
481/*
569ec282
KM
482 * An unexpected inconsistency occured.
483 * Die if preening, otherwise just print message and continue.
5d9906c0
KM
484 */
485/* VARARGS1 */
486pfatal(s, a1, a2, a3)
487 char *s;
488{
489
490 if (preen) {
491 printf("%s: ", devname);
492 printf(s, a1, a2, a3);
493 printf("\n");
7718c0e6
KM
494 printf("%s: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY.\n",
495 devname);
496 exit(8);
5d9906c0
KM
497 }
498 printf(s, a1, a2, a3);
499}
500
5d9906c0 501/*
569ec282 502 * Pwarn just prints a message when not preening,
5d9906c0
KM
503 * or a warning (preceded by filename) when preening.
504 */
505/* VARARGS1 */
506pwarn(s, a1, a2, a3, a4, a5, a6)
507 char *s;
508{
509
510 if (preen)
511 printf("%s: ", devname);
512 printf(s, a1, a2, a3, a4, a5, a6);
513}
514
515#ifndef lint
516/*
517 * Stub for routines from kernel.
518 */
519panic(s)
520 char *s;
521{
522
7718c0e6
KM
523 pfatal("INTERNAL INCONSISTENCY:");
524 errexit(s);
5d9906c0
KM
525}
526#endif