1 /* $NetBSD: utilities.c,v 1.20 2010/01/06 18:12:37 christos Exp $ */
4 * Copyright (c) 1980, 1986, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * Copyright (c) 1997 Manuel Bouyer.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
45 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
47 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
48 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
49 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
53 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 #include <sys/cdefs.h>
59 static char sccsid
[] = "@(#)utilities.c 8.1 (Berkeley) 6/5/93";
61 __RCSID("$NetBSD: utilities.c,v 1.20 2010/01/06 18:12:37 christos Exp $");
65 #include <sys/param.h>
67 #include <ufs/ext2fs/ext2fs_dinode.h>
68 #include <ufs/ext2fs/ext2fs_dir.h>
69 #include <ufs/ext2fs/ext2fs.h>
70 #include <ufs/ufs/dinode.h> /* for IFMT & friends */
82 #include "exitvalues.h"
84 long diskreads
, totalreads
; /* Disk cache statistics */
86 static void rwerror(const char *, daddr_t
);
88 extern volatile sig_atomic_t returntosingle
;
91 ftypeok(struct ext2fs_dinode
*dp
)
93 switch (fs2h16(dp
->e2di_mode
) & IFMT
) {
106 printf("bad file type 0%o\n", fs2h16(dp
->e2di_mode
));
112 reply(const char *question
)
118 pfatal("INTERNAL ERROR: GOT TO reply()");
119 persevere
= !strcmp(question
, "CONTINUE");
121 if (!persevere
&& (nflag
|| fswritefd
< 0)) {
122 printf("%s? no\n\n", question
);
125 if (yflag
|| (persevere
&& nflag
)) {
126 printf("%s? yes\n\n", question
);
130 printf("%s? [yn] ", question
);
131 (void) fflush(stdout
);
133 while (c
!= '\n' && getc(stdin
) != '\n')
136 } while (c
!= 'y' && c
!= 'Y' && c
!= 'n' && c
!= 'N');
138 if (c
== 'y' || c
== 'Y')
144 * Malloc buffers and set up cache.
153 diskreads
= totalreads
= 0;
154 pbp
= pdirbp
= (struct bufarea
*)0;
155 bufhead
.b_next
= bufhead
.b_prev
= &bufhead
;
156 bufcnt
= MAXBUFSPACE
/ sblock
.e2fs_bsize
;
157 if (bufcnt
< MINBUFS
)
159 for (i
= 0; i
< bufcnt
; i
++) {
160 bp
= malloc(sizeof(struct bufarea
));
161 bufp
= malloc((size_t)sblock
.e2fs_bsize
);
162 if (bp
== NULL
|| bufp
== NULL
) {
167 errexit("cannot allocate buffer pool");
169 bp
->b_un
.b_buf
= bufp
;
170 bp
->b_prev
= &bufhead
;
171 bp
->b_next
= bufhead
.b_next
;
172 bufhead
.b_next
->b_prev
= bp
;
176 bufhead
.b_size
= i
; /* save number of buffers */
180 * Manage a cache of directory blocks.
183 getdatablk(daddr_t blkno
, long size
)
187 for (bp
= bufhead
.b_next
; bp
!= &bufhead
; bp
= bp
->b_next
)
188 if (bp
->b_bno
== fsbtodb(&sblock
, blkno
))
190 for (bp
= bufhead
.b_prev
; bp
!= &bufhead
; bp
= bp
->b_prev
)
191 if ((bp
->b_flags
& B_INUSE
) == 0)
194 errexit("deadlocked buffer pool");
195 getblk(bp
, blkno
, size
);
200 bp
->b_prev
->b_next
= bp
->b_next
;
201 bp
->b_next
->b_prev
= bp
->b_prev
;
202 bp
->b_prev
= &bufhead
;
203 bp
->b_next
= bufhead
.b_next
;
204 bufhead
.b_next
->b_prev
= bp
;
206 bp
->b_flags
|= B_INUSE
;
211 getblk(struct bufarea
*bp
, daddr_t blk
, long size
)
215 dblk
= fsbtodb(&sblock
, blk
);
216 if (bp
->b_bno
!= dblk
) {
217 flush(fswritefd
, bp
);
218 bp
->b_errs
= bread(fsreadfd
, bp
->b_un
.b_buf
, dblk
, size
);
225 flush(int fd
, struct bufarea
*bp
)
232 pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n",
233 (bp
->b_errs
== bp
->b_size
/ dev_bsize
) ? "" : "PARTIALLY ",
234 (long long)bp
->b_bno
);
237 bwrite(fd
, bp
->b_un
.b_buf
, bp
->b_bno
, (long)bp
->b_size
);
240 for (i
= 0; i
< sblock
.e2fs_ngdb
; i
++) {
241 bwrite(fswritefd
, (char *)
242 &sblock
.e2fs_gd
[i
* sblock
.e2fs_bsize
/ sizeof(struct ext2_gd
)],
243 fsbtodb(&sblock
, ((sblock
.e2fs_bsize
>1024)?0:1)+i
+1),
249 rwerror(const char *mesg
, daddr_t blk
)
254 pfatal("CANNOT %s: BLK %lld", mesg
, (long long)blk
);
255 if (reply("CONTINUE") == 0)
256 errexit("Program terminated");
260 ckfini(int markclean
)
262 struct bufarea
*bp
, *nbp
;
266 (void)close(fsreadfd
);
269 flush(fswritefd
, &sblk
);
270 if (havesb
&& sblk
.b_bno
!= SBOFF
/ dev_bsize
&&
271 !preen
&& reply("UPDATE STANDARD SUPERBLOCKS")) {
272 sblk
.b_bno
= SBOFF
/ dev_bsize
;
274 flush(fswritefd
, &sblk
);
277 flush(fswritefd
, &asblk
);
279 for (bp
= bufhead
.b_prev
; bp
&& bp
!= &bufhead
; bp
= nbp
) {
281 flush(fswritefd
, bp
);
283 free(bp
->b_un
.b_buf
);
286 if (bufhead
.b_size
!= cnt
)
287 errexit("Panic: lost %d buffers", bufhead
.b_size
- cnt
);
288 pbp
= pdirbp
= (struct bufarea
*)0;
289 if (markclean
&& (sblock
.e2fs
.e2fs_state
& E2FS_ISCLEAN
) == 0) {
291 * Mark the file system as clean, and sync the superblock.
294 pwarn("MARKING FILE SYSTEM CLEAN\n");
295 else if (!reply("MARK FILE SYSTEM CLEAN"))
298 sblock
.e2fs
.e2fs_state
= E2FS_ISCLEAN
;
300 flush(fswritefd
, &sblk
);
304 printf("cache missed %ld of %ld (%d%%)\n", diskreads
,
305 totalreads
, (int)(diskreads
* 100 / totalreads
));
306 (void)close(fsreadfd
);
307 (void)close(fswritefd
);
311 bread(int fd
, char *buf
, daddr_t blk
, long size
)
319 if (lseek(fd
, offset
, 0) < 0)
320 rwerror("SEEK", blk
);
321 else if (read(fd
, buf
, (int)size
) == size
)
323 rwerror("READ", blk
);
324 if (lseek(fd
, offset
, 0) < 0)
325 rwerror("SEEK", blk
);
327 memset(buf
, 0, (size_t)size
);
328 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
329 for (cp
= buf
, i
= 0; i
< size
; i
+= secsize
, cp
+= secsize
) {
330 if (read(fd
, cp
, (int)secsize
) != secsize
) {
331 (void)lseek(fd
, offset
+ i
+ secsize
, 0);
332 if (secsize
!= dev_bsize
&& dev_bsize
!= 1)
333 printf(" %lld (%lld),",
334 (long long)((blk
*dev_bsize
+ i
) / secsize
),
335 (long long)(blk
+ i
/ dev_bsize
));
337 printf(" %lld,", (long long)(blk
+
347 bwrite(int fd
, char *buf
, daddr_t blk
, long size
)
357 if (lseek(fd
, offset
, 0) < 0)
358 rwerror("SEEK", blk
);
359 else if (write(fd
, buf
, (int)size
) == size
) {
363 rwerror("WRITE", blk
);
364 if (lseek(fd
, offset
, 0) < 0)
365 rwerror("SEEK", blk
);
366 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
367 for (cp
= buf
, i
= 0; i
< size
; i
+= dev_bsize
, cp
+= dev_bsize
)
368 if (write(fd
, cp
, (int)dev_bsize
) != dev_bsize
) {
369 (void)lseek(fd
, offset
+ i
+ dev_bsize
, 0);
370 printf(" %lld,", (long long)(blk
+ i
/ dev_bsize
));
377 * allocate a data block
384 for (i
= 0; i
< maxfsblock
- 1; i
++) {
395 * Free a previously allocated block
398 freeblk(daddr_t blkno
)
400 struct inodesc idesc
;
402 idesc
.id_blkno
= blkno
;
403 idesc
.id_numfrags
= 1;
404 (void)pass4check(&idesc
);
411 getpathname(char *namebuf
, size_t namebuflen
, ino_t curdir
, ino_t ino
)
415 struct inodesc idesc
;
418 if (curdir
== ino
&& ino
== EXT2_ROOTINO
) {
419 (void)strlcpy(namebuf
, "/", namebuflen
);
423 (statemap
[curdir
] != DSTATE
&& statemap
[curdir
] != DFOUND
)) {
424 (void)strlcpy(namebuf
, "?", namebuflen
);
428 memset(&idesc
, 0, sizeof(struct inodesc
));
429 idesc
.id_type
= DATA
;
430 idesc
.id_fix
= IGNORE
;
431 cp
= &namebuf
[MAXPATHLEN
- 1];
434 idesc
.id_parent
= curdir
;
437 while (ino
!= EXT2_ROOTINO
) {
438 idesc
.id_number
= ino
;
439 idesc
.id_func
= findino
;
440 idesc
.id_name
= "..";
441 if ((ckinode(ginode(ino
), &idesc
) & FOUND
) == 0)
444 idesc
.id_number
= idesc
.id_parent
;
445 idesc
.id_parent
= ino
;
446 idesc
.id_func
= findname
;
447 idesc
.id_name
= namebuf
;
448 if ((ckinode(ginode(idesc
.id_number
), &idesc
)&FOUND
) == 0)
450 len
= strlen(namebuf
);
452 memcpy(cp
, namebuf
, (size_t)len
);
454 if (cp
< &namebuf
[EXT2FS_MAXNAMLEN
])
456 ino
= idesc
.id_number
;
459 if (ino
!= EXT2_ROOTINO
)
461 memcpy(namebuf
, cp
, (size_t)(&namebuf
[MAXPATHLEN
] - cp
));
468 _exit(FSCK_EXIT_SIGNALLED
);
472 * When preening, allow a single quit to signal
473 * a special exit after filesystem checks complete
474 * so that reboot sequence may be interrupted.
479 static const char msg
[] =
480 "returning to single-user after filesystem check\n";
483 (void)write(STDOUT_FILENO
, msg
, sizeof(msg
) - 1);
485 (void)signal(SIGQUIT
, SIG_DFL
);
490 * Ignore a single quit signal; wait and flush just in case.
491 * Used by child processes in preen.
499 (void)signal(SIGQUIT
, SIG_IGN
);
500 (void)signal(SIGQUIT
, SIG_DFL
);
505 * determine whether an inode should be fixed.
508 dofix(struct inodesc
*idesc
, const char *msg
)
511 switch (idesc
->id_fix
) {
514 if (idesc
->id_type
== DATA
)
515 direrror(idesc
->id_number
, msg
);
519 printf(" (SALVAGED)\n");
523 if (reply("SALVAGE") == 0) {
524 idesc
->id_fix
= NOFIX
;
538 errexit("UNKNOWN INODESC FIX MODE %d", idesc
->id_fix
);