utilities.c revision 1.23 1 /* $NetBSD: utilities.c,v 1.23 1998/03/18 17:01:24 bouyer Exp $ */
2
3 /*
4 * Copyright (c) 1980, 1986, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95";
40 #else
41 __RCSID("$NetBSD: utilities.c,v 1.23 1998/03/18 17:01:24 bouyer Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include <sys/param.h>
46 #include <sys/time.h>
47
48 #include <ufs/ufs/dinode.h>
49 #include <ufs/ufs/dir.h>
50 #include <ufs/ffs/fs.h>
51 #include <ufs/ffs/ffs_extern.h>
52
53 #include <ctype.h>
54 #include <err.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <unistd.h>
59
60 #include "fsutil.h"
61 #include "fsck.h"
62 #include "extern.h"
63
64 long diskreads, totalreads; /* Disk cache statistics */
65
66 static void rwerror __P((char *, ufs_daddr_t));
67
68 int
69 ftypeok(dp)
70 struct dinode *dp;
71 {
72 switch (iswap16(dp->di_mode) & IFMT) {
73
74 case IFDIR:
75 case IFREG:
76 case IFBLK:
77 case IFCHR:
78 case IFLNK:
79 case IFSOCK:
80 case IFIFO:
81 return (1);
82
83 default:
84 if (debug)
85 printf("bad file type 0%o\n", iswap16(dp->di_mode));
86 return (0);
87 }
88 }
89
90 int
91 reply(question)
92 char *question;
93 {
94 int persevere;
95 char c;
96
97 if (preen)
98 pfatal("INTERNAL ERROR: GOT TO reply()");
99 persevere = !strcmp(question, "CONTINUE");
100 printf("\n");
101 if (!persevere && (nflag || fswritefd < 0)) {
102 printf("%s? no\n\n", question);
103 return (0);
104 }
105 if (yflag || (persevere && nflag)) {
106 printf("%s? yes\n\n", question);
107 return (1);
108 }
109 do {
110 printf("%s? [yn] ", question);
111 (void) fflush(stdout);
112 c = getc(stdin);
113 while (c != '\n' && getc(stdin) != '\n')
114 if (feof(stdin))
115 return (0);
116 } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
117 printf("\n");
118 if (c == 'y' || c == 'Y')
119 return (1);
120 return (0);
121 }
122
123 /*
124 * Malloc buffers and set up cache.
125 */
126 void
127 bufinit()
128 {
129 struct bufarea *bp;
130 long bufcnt, i;
131 char *bufp;
132
133 pbp = pdirbp = (struct bufarea *)0;
134 bufp = malloc((unsigned int)sblock->fs_bsize);
135 if (bufp == 0)
136 errx(EEXIT, "cannot allocate buffer pool");
137 cgblk.b_un.b_buf = bufp;
138 initbarea(&cgblk);
139 bufhead.b_next = bufhead.b_prev = &bufhead;
140 bufcnt = MAXBUFSPACE / sblock->fs_bsize;
141 if (bufcnt < MINBUFS)
142 bufcnt = MINBUFS;
143 for (i = 0; i < bufcnt; i++) {
144 bp = (struct bufarea *)malloc(sizeof(struct bufarea));
145 bufp = malloc((unsigned int)sblock->fs_bsize);
146 if (bp == NULL || bufp == NULL) {
147 if (i >= MINBUFS)
148 break;
149 errx(EEXIT, "cannot allocate buffer pool");
150 }
151 bp->b_un.b_buf = bufp;
152 bp->b_prev = &bufhead;
153 bp->b_next = bufhead.b_next;
154 bufhead.b_next->b_prev = bp;
155 bufhead.b_next = bp;
156 initbarea(bp);
157 }
158 bufhead.b_size = i; /* save number of buffers */
159 }
160
161 /*
162 * Manage a cache of directory blocks.
163 */
164 struct bufarea *
165 getdatablk(blkno, size)
166 ufs_daddr_t blkno;
167 long size;
168 {
169 struct bufarea *bp;
170
171 for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
172 if (bp->b_bno == fsbtodb(sblock, blkno))
173 goto foundit;
174 for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
175 if ((bp->b_flags & B_INUSE) == 0)
176 break;
177 if (bp == &bufhead)
178 errx(EEXIT, "deadlocked buffer pool");
179 getblk(bp, blkno, size);
180 /* fall through */
181 foundit:
182 totalreads++;
183 bp->b_prev->b_next = bp->b_next;
184 bp->b_next->b_prev = bp->b_prev;
185 bp->b_prev = &bufhead;
186 bp->b_next = bufhead.b_next;
187 bufhead.b_next->b_prev = bp;
188 bufhead.b_next = bp;
189 bp->b_flags |= B_INUSE;
190 return (bp);
191 }
192
193 void
194 getblk(bp, blk, size)
195 struct bufarea *bp;
196 ufs_daddr_t blk;
197 long size;
198 {
199 ufs_daddr_t dblk;
200
201 dblk = fsbtodb(sblock, blk);
202 if (bp->b_bno != dblk) {
203 flush(fswritefd, bp);
204 diskreads++;
205 bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size);
206 bp->b_bno = dblk;
207 bp->b_size = size;
208 }
209 }
210
211 void
212 flush(fd, bp)
213 int fd;
214 struct bufarea *bp;
215 {
216 int i, j;
217
218 if (!bp->b_dirty)
219 return;
220 if (bp->b_errs != 0)
221 pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
222 (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
223 bp->b_bno);
224 bp->b_dirty = 0;
225 bp->b_errs = 0;
226 bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
227 if (bp != &sblk)
228 return;
229 for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) {
230 int size = sblock->fs_cssize - i < sblock->fs_bsize ?
231 sblock->fs_cssize - i : sblock->fs_bsize;
232 /*
233 * The following routines assumes that struct csum is made of
234 * u_int32_t's
235 */
236 if (needswap) {
237 u_int32_t *cd = (u_int32_t *)sblock->fs_csp[j];
238 int k;
239 for (k = 0; k < size / sizeof(u_int32_t); k++)
240 cd[k] = bswap32(cd[k]);
241 }
242 bwrite(fswritefd, (char *)sblock->fs_csp[j],
243 fsbtodb(sblock, sblock->fs_csaddr + j * sblock->fs_frag),
244 sblock->fs_cssize - i < sblock->fs_bsize ?
245 sblock->fs_cssize - i : sblock->fs_bsize);
246 if (needswap) {
247 u_int32_t *cd = (u_int32_t *)sblock->fs_csp[j];
248 int k;
249 for (k = 0; k < size / sizeof(u_int32_t); k++)
250 cd[k] = bswap32(cd[k]);
251 }
252 }
253 }
254
255 static void
256 rwerror(mesg, blk)
257 char *mesg;
258 ufs_daddr_t blk;
259 {
260
261 if (preen == 0)
262 printf("\n");
263 pfatal("CANNOT %s: BLK %d", mesg, blk);
264 if (reply("CONTINUE") == 0)
265 exit(EEXIT);
266 }
267
268 void
269 ckfini()
270 {
271 struct bufarea *bp, *nbp;
272 int ofsmodified, cnt = 0;
273
274 if (fswritefd < 0) {
275 (void)close(fsreadfd);
276 return;
277 }
278 flush(fswritefd, &sblk);
279 if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
280 !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
281 sblk.b_bno = SBOFF / dev_bsize;
282 sbdirty();
283 flush(fswritefd, &sblk);
284 }
285 flush(fswritefd, &cgblk);
286 free(cgblk.b_un.b_buf);
287 for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
288 cnt++;
289 flush(fswritefd, bp);
290 nbp = bp->b_prev;
291 free(bp->b_un.b_buf);
292 free((char *)bp);
293 }
294 if (bufhead.b_size != cnt)
295 errx(EEXIT, "Panic: lost %d buffers", bufhead.b_size - cnt);
296 pbp = pdirbp = (struct bufarea *)0;
297 if (markclean && (sblock->fs_clean & FS_ISCLEAN) == 0) {
298 /*
299 * Mark the file system as clean, and sync the superblock.
300 */
301 if (preen)
302 pwarn("MARKING FILE SYSTEM CLEAN\n");
303 else if (!reply("MARK FILE SYSTEM CLEAN"))
304 markclean = 0;
305 if (markclean) {
306 sblock->fs_clean = FS_ISCLEAN;
307 sbdirty();
308 ofsmodified = fsmodified;
309 flush(fswritefd, &sblk);
310 #if LITE2BORKEN
311 fsmodified = ofsmodified;
312 #endif
313 if (!preen)
314 printf(
315 "\n***** FILE SYSTEM MARKED CLEAN *****\n");
316 }
317 }
318 if (debug)
319 printf("cache missed %ld of %ld (%d%%)\n", diskreads,
320 totalreads, (int)(diskreads * 100 / totalreads));
321 (void)close(fsreadfd);
322 (void)close(fswritefd);
323 }
324
325 int
326 bread(fd, buf, blk, size)
327 int fd;
328 char *buf;
329 ufs_daddr_t blk;
330 long size;
331 {
332 char *cp;
333 int i, errs;
334 off_t offset;
335
336 offset = blk;
337 offset *= dev_bsize;
338 if (lseek(fd, offset, 0) < 0)
339 rwerror("SEEK", blk);
340 else if (read(fd, buf, (int)size) == size)
341 return (0);
342 rwerror("READ", blk);
343 if (lseek(fd, offset, 0) < 0)
344 rwerror("SEEK", blk);
345 errs = 0;
346 memset(buf, 0, (size_t)size);
347 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
348 for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
349 if (read(fd, cp, (int)secsize) != secsize) {
350 (void)lseek(fd, offset + i + secsize, 0);
351 if (secsize != dev_bsize && dev_bsize != 1)
352 printf(" %ld (%ld),",
353 (blk * dev_bsize + i) / secsize,
354 blk + i / dev_bsize);
355 else
356 printf(" %ld,", blk + i / dev_bsize);
357 errs++;
358 }
359 }
360 printf("\n");
361 return (errs);
362 }
363
364 void
365 bwrite(fd, buf, blk, size)
366 int fd;
367 char *buf;
368 ufs_daddr_t blk;
369 long size;
370 {
371 int i;
372 char *cp;
373 off_t offset;
374
375 if (fd < 0)
376 return;
377 offset = blk;
378 offset *= dev_bsize;
379 if (lseek(fd, offset, 0) < 0)
380 rwerror("SEEK", blk);
381 else if (write(fd, buf, (int)size) == size) {
382 fsmodified = 1;
383 return;
384 }
385 rwerror("WRITE", blk);
386 if (lseek(fd, offset, 0) < 0)
387 rwerror("SEEK", blk);
388 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
389 for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
390 if (write(fd, cp, (int)dev_bsize) != dev_bsize) {
391 (void)lseek(fd, offset + i + dev_bsize, 0);
392 printf(" %ld,", blk + i / dev_bsize);
393 }
394 printf("\n");
395 return;
396 }
397
398 /*
399 * allocate a data block with the specified number of fragments
400 */
401 ufs_daddr_t
402 allocblk(frags)
403 long frags;
404 {
405 int i, j, k;
406
407 if (frags <= 0 || frags > sblock->fs_frag)
408 return (0);
409 for (i = 0; i < maxfsblock - sblock->fs_frag; i += sblock->fs_frag) {
410 for (j = 0; j <= sblock->fs_frag - frags; j++) {
411 if (testbmap(i + j))
412 continue;
413 for (k = 1; k < frags; k++)
414 if (testbmap(i + j + k))
415 break;
416 if (k < frags) {
417 j += k;
418 continue;
419 }
420 for (k = 0; k < frags; k++)
421 setbmap(i + j + k);
422 n_blks += frags;
423 return (i + j);
424 }
425 }
426 return (0);
427 }
428
429 /*
430 * Free a previously allocated block
431 */
432 void
433 freeblk(blkno, frags)
434 ufs_daddr_t blkno;
435 long frags;
436 {
437 struct inodesc idesc;
438
439 idesc.id_blkno = blkno;
440 idesc.id_numfrags = frags;
441 (void)pass4check(&idesc);
442 }
443
444 /*
445 * Find a pathname
446 */
447 void
448 getpathname(namebuf, curdir, ino)
449 char *namebuf;
450 ino_t curdir, ino;
451 {
452 int len;
453 char *cp;
454 struct inodesc idesc;
455 static int busy = 0;
456
457 if (curdir == ino && ino == ROOTINO) {
458 (void)strcpy(namebuf, "/");
459 return;
460 }
461 if (busy ||
462 (statemap[curdir] != DSTATE && statemap[curdir] != DFOUND)) {
463 (void)strcpy(namebuf, "?");
464 return;
465 }
466 busy = 1;
467 memset(&idesc, 0, sizeof(struct inodesc));
468 idesc.id_type = DATA;
469 idesc.id_fix = IGNORE;
470 cp = &namebuf[MAXPATHLEN - 1];
471 *cp = '\0';
472 if (curdir != ino) {
473 idesc.id_parent = curdir;
474 goto namelookup;
475 }
476 while (ino != ROOTINO) {
477 idesc.id_number = ino;
478 idesc.id_func = findino;
479 idesc.id_name = "..";
480 if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
481 break;
482 namelookup:
483 idesc.id_number = idesc.id_parent;
484 idesc.id_parent = ino;
485 idesc.id_func = findname;
486 idesc.id_name = namebuf;
487 if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
488 break;
489 len = strlen(namebuf);
490 cp -= len;
491 memmove(cp, namebuf, (size_t)len);
492 *--cp = '/';
493 if (cp < &namebuf[MAXNAMLEN])
494 break;
495 ino = idesc.id_number;
496 }
497 busy = 0;
498 if (ino != ROOTINO)
499 *--cp = '?';
500 memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp));
501 }
502
503 void
504 catch(sig)
505 int sig;
506 {
507 if (!doinglevel2) {
508 markclean = 0;
509 ckfini();
510 }
511 exit(12);
512 }
513
514 /*
515 * When preening, allow a single quit to signal
516 * a special exit after filesystem checks complete
517 * so that reboot sequence may be interrupted.
518 */
519 void
520 catchquit(sig)
521 int sig;
522 {
523 extern returntosingle;
524
525 printf("returning to single-user after filesystem check\n");
526 returntosingle = 1;
527 (void)signal(SIGQUIT, SIG_DFL);
528 }
529
530 /*
531 * Ignore a single quit signal; wait and flush just in case.
532 * Used by child processes in preen.
533 */
534 void
535 voidquit(sig)
536 int sig;
537 {
538
539 sleep(1);
540 (void)signal(SIGQUIT, SIG_IGN);
541 (void)signal(SIGQUIT, SIG_DFL);
542 }
543
544 /*
545 * determine whether an inode should be fixed.
546 */
547 int
548 dofix(idesc, msg)
549 struct inodesc *idesc;
550 char *msg;
551 {
552
553 switch (idesc->id_fix) {
554
555 case DONTKNOW:
556 if (idesc->id_type == DATA)
557 direrror(idesc->id_number, msg);
558 else
559 pwarn(msg);
560 if (preen) {
561 printf(" (SALVAGED)\n");
562 idesc->id_fix = FIX;
563 return (ALTERED);
564 }
565 if (reply("SALVAGE") == 0) {
566 idesc->id_fix = NOFIX;
567 return (0);
568 }
569 idesc->id_fix = FIX;
570 return (ALTERED);
571
572 case FIX:
573 return (ALTERED);
574
575 case NOFIX:
576 case IGNORE:
577 return (0);
578
579 default:
580 errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix);
581 }
582 /* NOTREACHED */
583 return (0);
584 }
585
586 void copyback_cg(blk)
587 struct bufarea *blk;
588 {
589 memcpy(blk->b_un.b_cg, cgrp, SBSIZE);
590 if (needswap)
591 swap_cg(cgrp, blk->b_un.b_cg);
592 }
593
594 void
595 swap_cg(o, n)
596 struct cg *o, *n;
597 {
598 int i;
599 u_int32_t *n32, *o32;
600 u_int16_t *n16, *o16;
601
602 n->cg_firstfield = bswap32(o->cg_firstfield);
603 n->cg_magic = bswap32(o->cg_magic);
604 n->cg_time = bswap32(o->cg_time);
605 n->cg_cgx = bswap32(o->cg_cgx);
606 n->cg_ncyl = bswap16(o->cg_ncyl);
607 n->cg_niblk = bswap16(o->cg_niblk);
608 n->cg_ndblk = bswap32(o->cg_ndblk);
609 n->cg_cs.cs_ndir = bswap32(o->cg_cs.cs_ndir);
610 n->cg_cs.cs_nbfree = bswap32(o->cg_cs.cs_nbfree);
611 n->cg_cs.cs_nifree = bswap32(o->cg_cs.cs_nifree);
612 n->cg_cs.cs_nffree = bswap32(o->cg_cs.cs_nffree);
613 n->cg_rotor = bswap32(o->cg_rotor);
614 n->cg_frotor = bswap32(o->cg_frotor);
615 n->cg_irotor = bswap32(o->cg_irotor);
616 n->cg_btotoff = bswap32(o->cg_btotoff);
617 n->cg_boff = bswap32(o->cg_boff);
618 n->cg_iusedoff = bswap32(o->cg_iusedoff);
619 n->cg_freeoff = bswap32(o->cg_freeoff);
620 n->cg_nextfreeoff = bswap32(o->cg_nextfreeoff);
621 n->cg_clustersumoff = bswap32(o->cg_clustersumoff);
622 n->cg_clusteroff = bswap32(o->cg_clusteroff);
623 n->cg_nclusterblks = bswap32(o->cg_nclusterblks);
624 for (i=0; i < MAXFRAG; i++)
625 n->cg_frsum[i] = bswap32(o->cg_frsum[i]);
626
627 if (sblock->fs_postblformat == FS_42POSTBLFMT) { /* old format */
628 struct ocg *on, *oo;
629 int j;
630 on = (struct ocg *)n;
631 oo = (struct ocg *)o;
632 for(i = 0; i < 8; i++) {
633 on->cg_frsum[i] = bswap32(oo->cg_frsum[i]);
634 }
635 for(i = 0; i < 32; i++) {
636 on->cg_btot[i] = bswap32(oo->cg_btot[i]);
637 for (j = 0; j < 8; j++)
638 on->cg_b[i][j] = bswap16(oo->cg_b[i][j]);
639 }
640 memmove(on->cg_iused, oo->cg_iused, 256);
641 on->cg_magic = bswap32(oo->cg_magic);
642 } else { /* new format */
643 if (n->cg_magic == CG_MAGIC) {
644 n32 = (u_int32_t*)((u_int8_t*)n + n->cg_btotoff);
645 o32 = (u_int32_t*)((u_int8_t*)o + n->cg_btotoff);
646 n16 = (u_int16_t*)((u_int8_t*)n + n->cg_boff);
647 o16 = (u_int16_t*)((u_int8_t*)o + n->cg_boff);
648 } else {
649 n32 = (u_int32_t*)((u_int8_t*)n + o->cg_btotoff);
650 o32 = (u_int32_t*)((u_int8_t*)o + o->cg_btotoff);
651 n16 = (u_int16_t*)((u_int8_t*)n + o->cg_boff);
652 o16 = (u_int16_t*)((u_int8_t*)o + o->cg_boff);
653 }
654 for (i=0; i < sblock->fs_cpg; i++)
655 n32[i] = bswap32(o32[i]);
656
657 for (i=0; i < sblock->fs_cpg * sblock->fs_nrpos; i++)
658 n16[i] = bswap16(o16[i]);
659
660 if (n->cg_magic == CG_MAGIC) {
661 n32 = (u_int32_t*)((u_int8_t*)n + n->cg_clustersumoff);
662 o32 = (u_int32_t*)((u_int8_t*)o + n->cg_clustersumoff);
663 } else {
664 n32 = (u_int32_t*)((u_int8_t*)n + o->cg_clustersumoff);
665 o32 = (u_int32_t*)((u_int8_t*)o + o->cg_clustersumoff);
666 }
667 for (i = 0; i < sblock->fs_contigsumsize + 1; i++)
668 n32[i] = bswap32(o32[i]);
669 }
670 }
671