2 * Copyright (c) 1980, 1986, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * @(#)utilities.c 8.6 (Berkeley) 5/19/95
34 * $FreeBSD: src/sbin/fsck/utilities.c,v 1.11.2.3 2001/01/23 23:11:07 iedowse Exp $
35 * $DragonFly: src/sbin/fsck/utilities.c,v 1.10 2006/10/12 04:04:03 dillon Exp $
38 #include <sys/param.h>
40 #include <vfs/ufs/dinode.h>
41 #include <vfs/ufs/dir.h>
42 #include <vfs/ufs/fs.h>
49 long diskreads
, totalreads
; /* Disk cache statistics */
51 static void rwerror(char *mesg
, ufs_daddr_t blk
);
54 ftypeok(struct ufs1_dinode
*dp
)
56 switch (dp
->di_mode
& IFMT
) {
69 printf("bad file type 0%o\n", dp
->di_mode
);
81 pfatal("INTERNAL ERROR: GOT TO reply()");
82 persevere
= !strcmp(question
, "CONTINUE");
84 if (!persevere
&& (nflag
|| fswritefd
< 0)) {
85 printf("%s? no\n\n", question
);
89 if (yflag
|| (persevere
&& nflag
)) {
90 printf("%s? yes\n\n", question
);
94 printf("%s? [yn] ", question
);
97 while (c
!= '\n' && getc(stdin
) != '\n') {
103 } while (c
!= 'y' && c
!= 'Y' && c
!= 'n' && c
!= 'N');
105 if (c
== 'y' || c
== 'Y')
112 * Look up state information for an inode.
115 inoinfo(ufs1_ino_t inum
)
117 static struct inostat unallocated
= { USTATE
, 0, 0 };
118 struct inostatlist
*ilp
;
122 errx(EEXIT
, "inoinfo: inumber %d out of range", inum
);
123 ilp
= &inostathead
[inum
/ sblock
.fs_ipg
];
124 iloff
= inum
% sblock
.fs_ipg
;
125 if (iloff
>= ilp
->il_numalloced
)
126 return (&unallocated
);
127 return (&ilp
->il_stat
[iloff
]);
131 * Malloc buffers and set up cache.
140 pbp
= pdirbp
= (struct bufarea
*)0;
141 bufp
= malloc((unsigned int)sblock
.fs_bsize
);
143 errx(EEXIT
, "cannot allocate buffer pool");
144 cgblk
.b_un
.b_buf
= bufp
;
146 bufhead
.b_next
= bufhead
.b_prev
= &bufhead
;
147 bufcnt
= MAXBUFSPACE
/ sblock
.fs_bsize
;
148 if (bufcnt
< MINBUFS
)
150 for (i
= 0; i
< bufcnt
; i
++) {
151 bp
= (struct bufarea
*)malloc(sizeof(struct bufarea
));
152 bufp
= malloc((unsigned int)sblock
.fs_bsize
);
153 if (bp
== NULL
|| bufp
== NULL
) {
156 errx(EEXIT
, "cannot allocate buffer pool");
158 bp
->b_un
.b_buf
= bufp
;
159 bp
->b_prev
= &bufhead
;
160 bp
->b_next
= bufhead
.b_next
;
161 bufhead
.b_next
->b_prev
= bp
;
165 bufhead
.b_size
= i
; /* save number of buffers */
169 * Manage a cache of directory blocks.
172 getdatablk(ufs_daddr_t blkno
, long size
)
176 for (bp
= bufhead
.b_next
; bp
!= &bufhead
; bp
= bp
->b_next
)
177 if (bp
->b_bno
== fsbtodb(&sblock
, blkno
))
179 for (bp
= bufhead
.b_prev
; bp
!= &bufhead
; bp
= bp
->b_prev
)
180 if ((bp
->b_flags
& B_INUSE
) == 0)
183 errx(EEXIT
, "deadlocked buffer pool");
184 getblk(bp
, blkno
, size
);
188 bp
->b_prev
->b_next
= bp
->b_next
;
189 bp
->b_next
->b_prev
= bp
->b_prev
;
190 bp
->b_prev
= &bufhead
;
191 bp
->b_next
= bufhead
.b_next
;
192 bufhead
.b_next
->b_prev
= bp
;
194 bp
->b_flags
|= B_INUSE
;
199 getblk(struct bufarea
*bp
, ufs_daddr_t blk
, long size
)
203 dblk
= fsbtodb(&sblock
, blk
);
204 if (bp
->b_bno
!= dblk
) {
205 flush(fswritefd
, bp
);
207 bp
->b_errs
= bread(fsreadfd
, bp
->b_un
.b_buf
, dblk
, size
);
214 flush(int fd
, struct bufarea
*bp
)
221 pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
222 (bp
->b_errs
== bp
->b_size
/ dev_bsize
) ? "" : "PARTIALLY ",
226 bwrite(fd
, bp
->b_un
.b_buf
, bp
->b_bno
, (long)bp
->b_size
);
229 for (i
= 0, j
= 0; i
< sblock
.fs_cssize
; i
+= sblock
.fs_bsize
, j
++) {
230 bwrite(fswritefd
, (char *)sblock
.fs_csp
+ i
,
231 fsbtodb(&sblock
, sblock
.fs_csaddr
+ j
* sblock
.fs_frag
),
232 sblock
.fs_cssize
- i
< sblock
.fs_bsize
?
233 sblock
.fs_cssize
- i
: sblock
.fs_bsize
);
238 rwerror(char *mesg
, ufs_daddr_t blk
)
243 pfatal("CANNOT %s: BLK %ld", mesg
, blk
);
244 if (reply("CONTINUE") == 0)
249 ckfini(int markclean
)
251 struct bufarea
*bp
, *nbp
;
252 int ofsmodified
, cnt
= 0;
258 flush(fswritefd
, &sblk
);
259 if (havesb
&& sblk
.b_bno
!= SBOFF
/ dev_bsize
&&
260 !preen
&& reply("UPDATE STANDARD SUPERBLOCK")) {
261 sblk
.b_bno
= SBOFF
/ dev_bsize
;
263 flush(fswritefd
, &sblk
);
265 flush(fswritefd
, &cgblk
);
266 free(cgblk
.b_un
.b_buf
);
267 for (bp
= bufhead
.b_prev
; bp
&& bp
!= &bufhead
; bp
= nbp
) {
269 flush(fswritefd
, bp
);
271 free(bp
->b_un
.b_buf
);
274 if (bufhead
.b_size
!= cnt
)
275 errx(EEXIT
, "panic: lost %d buffers", bufhead
.b_size
- cnt
);
276 pbp
= pdirbp
= (struct bufarea
*)0;
277 if (sblock
.fs_clean
!= markclean
) {
278 sblock
.fs_clean
= markclean
;
280 ofsmodified
= fsmodified
;
281 flush(fswritefd
, &sblk
);
282 fsmodified
= ofsmodified
;
284 printf("\n***** FILE SYSTEM MARKED %s *****\n",
285 markclean
? "CLEAN" : "DIRTY");
289 } else if (!preen
&& !markclean
) {
290 printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
294 printf("cache missed %ld of %ld (%d%%)\n", diskreads
,
295 totalreads
, (int)(diskreads
* 100 / totalreads
));
301 bread(int fd
, char *buf
, ufs_daddr_t blk
, long size
)
309 if (lseek(fd
, offset
, 0) < 0)
310 rwerror("SEEK", blk
);
311 else if (read(fd
, buf
, (int)size
) == size
)
313 rwerror("READ", blk
);
314 if (lseek(fd
, offset
, 0) < 0)
315 rwerror("SEEK", blk
);
317 memset(buf
, 0, (size_t)size
);
318 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
319 for (cp
= buf
, i
= 0; i
< size
; i
+= secsize
, cp
+= secsize
) {
320 if (read(fd
, cp
, (int)secsize
) != secsize
) {
321 lseek(fd
, offset
+ i
+ secsize
, 0);
322 if (secsize
!= dev_bsize
&& dev_bsize
!= 1)
323 printf(" %ld (%ld),",
324 (blk
* dev_bsize
+ i
) / secsize
,
325 blk
+ i
/ dev_bsize
);
327 printf(" %ld,", blk
+ i
/ dev_bsize
);
338 bwrite(int fd
, char *buf
, ufs_daddr_t blk
, long size
)
348 if (lseek(fd
, offset
, 0) < 0)
349 rwerror("SEEK", blk
);
350 else if (write(fd
, buf
, (int)size
) == size
) {
355 rwerror("WRITE", blk
);
356 if (lseek(fd
, offset
, 0) < 0)
357 rwerror("SEEK", blk
);
358 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
359 for (cp
= buf
, i
= 0; i
< size
; i
+= dev_bsize
, cp
+= dev_bsize
)
360 if (write(fd
, cp
, (int)dev_bsize
) != dev_bsize
) {
361 lseek(fd
, offset
+ i
+ dev_bsize
, 0);
362 printf(" %ld,", blk
+ i
/ dev_bsize
);
369 * allocate a data block with the specified number of fragments
374 int i
, j
, k
, cg
, baseblk
;
375 struct cg
*cgp
= &cgrp
;
377 if (frags
<= 0 || frags
> sblock
.fs_frag
)
379 for (i
= 0; i
< maxfsblock
- sblock
.fs_frag
; i
+= sblock
.fs_frag
) {
380 for (j
= 0; j
<= sblock
.fs_frag
- frags
; j
++) {
383 for (k
= 1; k
< frags
; k
++)
384 if (testbmap(i
+ j
+ k
))
390 cg
= dtog(&sblock
, i
+ j
);
391 getblk(&cgblk
, cgtod(&sblock
, cg
), sblock
.fs_cgsize
);
392 if (!cg_chkmagic(cgp
))
393 pfatal("CG %d: BAD MAGIC NUMBER\n", cg
);
394 baseblk
= dtogd(&sblock
, i
+ j
);
395 for (k
= 0; k
< frags
; k
++) {
397 clrbit(cg_blksfree(cgp
), baseblk
+ k
);
400 if (frags
== sblock
.fs_frag
)
401 cgp
->cg_cs
.cs_nbfree
--;
403 cgp
->cg_cs
.cs_nffree
-= frags
;
412 * Free a previously allocated block
415 freeblk(ufs_daddr_t blkno
, long frags
)
417 struct inodesc idesc
;
419 idesc
.id_blkno
= blkno
;
420 idesc
.id_numfrags
= frags
;
428 getpathname(char *namebuf
, ufs1_ino_t curdir
, ufs1_ino_t ino
)
432 struct inodesc idesc
;
435 if (curdir
== ino
&& ino
== ROOTINO
) {
436 strcpy(namebuf
, "/");
440 (inoinfo(curdir
)->ino_state
!= DSTATE
&&
441 inoinfo(curdir
)->ino_state
!= DFOUND
)) {
442 strcpy(namebuf
, "?");
446 memset(&idesc
, 0, sizeof(struct inodesc
));
447 idesc
.id_type
= DATA
;
448 idesc
.id_fix
= IGNORE
;
449 cp
= &namebuf
[MAXPATHLEN
- 1];
452 idesc
.id_parent
= curdir
;
455 while (ino
!= ROOTINO
) {
456 idesc
.id_number
= ino
;
457 idesc
.id_func
= findino
;
458 idesc
.id_name
= "..";
459 if ((ckinode(ginode(ino
), &idesc
) & FOUND
) == 0)
462 idesc
.id_number
= idesc
.id_parent
;
463 idesc
.id_parent
= ino
;
464 idesc
.id_func
= findname
;
465 idesc
.id_name
= namebuf
;
466 if ((ckinode(ginode(idesc
.id_number
), &idesc
)&FOUND
) == 0)
468 len
= strlen(namebuf
);
470 memmove(cp
, namebuf
, (size_t)len
);
472 if (cp
< &namebuf
[MAXNAMLEN
])
474 ino
= idesc
.id_number
;
479 memmove(namebuf
, cp
, (size_t)(&namebuf
[MAXPATHLEN
] - cp
));
492 * When preening, allow a single quit to signal
493 * a special exit after filesystem checks complete
494 * so that reboot sequence may be interrupted.
500 printf("returning to single-user after filesystem check\n");
502 signal(SIGQUIT
, SIG_DFL
);
506 * Ignore a single quit signal; wait and flush just in case.
507 * Used by child processes in preen.
515 signal(SIGQUIT
, SIG_IGN
);
516 signal(SIGQUIT
, SIG_DFL
);
527 * determine whether an inode should be fixed.
530 dofix(struct inodesc
*idesc
, char *msg
)
533 switch (idesc
->id_fix
) {
536 if (idesc
->id_type
== DATA
)
537 direrror(idesc
->id_number
, msg
);
541 printf(" (SALVAGED)\n");
545 if (reply("SALVAGE") == 0) {
546 idesc
->id_fix
= NOFIX
;
560 errx(EEXIT
, "UNKNOWN INODESC FIX MODE %d", idesc
->id_fix
);
569 * An unexpected inconsistency occured.
570 * Die if preening or filesystem is running with soft dependency protocol,
571 * otherwise just print message and continue.
574 pfatal(const char *fmt
, ...)
579 vfprintf(stderr
, fmt
, ap
);
583 "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n");
586 if (cdevname
== NULL
)
588 fprintf(stderr
, "%s: ", cdevname
);
589 vfprintf(stderr
, fmt
, ap
);
591 "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n",
592 cdevname
, usedsoftdep
? " SOFT UPDATE " : " ");
598 * Pwarn just prints a message when not preening or running soft dependency
599 * protocol, or a warning (preceded by filename) when preening.
602 pwarn(const char *fmt
, ...)
607 fprintf(stderr
, "%s: ", cdevname
);
608 vfprintf(stderr
, fmt
, ap
);
613 * Stub for routines from kernel.
616 panic(const char *fmt
, ...)
621 pfatal("INTERNAL INCONSISTENCY:");
622 vfprintf(stderr
, fmt
, ap
);