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