1 /* $NetBSD: utilities.c,v 1.22 2011/06/09 19:57:51 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.22 2011/06/09 19:57:51 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
);
89 ftypeok(struct ext2fs_dinode
*dp
)
91 switch (fs2h16(dp
->e2di_mode
) & IFMT
) {
104 printf("bad file type 0%o\n", fs2h16(dp
->e2di_mode
));
110 reply(const char *question
)
116 pfatal("INTERNAL ERROR: GOT TO reply()");
117 persevere
= !strcmp(question
, "CONTINUE");
119 if (!persevere
&& (nflag
|| fswritefd
< 0)) {
120 printf("%s? no\n\n", question
);
123 if (yflag
|| (persevere
&& nflag
)) {
124 printf("%s? yes\n\n", question
);
128 printf("%s? [yn] ", question
);
129 (void) fflush(stdout
);
131 while (c
!= '\n' && getc(stdin
) != '\n')
134 } while (c
!= 'y' && c
!= 'Y' && c
!= 'n' && c
!= 'N');
136 if (c
== 'y' || c
== 'Y')
142 * Malloc buffers and set up cache.
151 diskreads
= totalreads
= 0;
152 pbp
= pdirbp
= (struct bufarea
*)0;
153 bufhead
.b_next
= bufhead
.b_prev
= &bufhead
;
154 bufcnt
= MAXBUFSPACE
/ sblock
.e2fs_bsize
;
155 if (bufcnt
< MINBUFS
)
157 for (i
= 0; i
< bufcnt
; i
++) {
158 bp
= malloc(sizeof(struct bufarea
));
159 bufp
= malloc((size_t)sblock
.e2fs_bsize
);
160 if (bp
== NULL
|| bufp
== NULL
) {
165 errexit("cannot allocate buffer pool");
167 bp
->b_un
.b_buf
= bufp
;
168 bp
->b_prev
= &bufhead
;
169 bp
->b_next
= bufhead
.b_next
;
170 bufhead
.b_next
->b_prev
= bp
;
174 bufhead
.b_size
= i
; /* save number of buffers */
178 * Manage a cache of directory blocks.
181 getdatablk(daddr_t blkno
, long size
)
185 for (bp
= bufhead
.b_next
; bp
!= &bufhead
; bp
= bp
->b_next
)
186 if (bp
->b_bno
== fsbtodb(&sblock
, blkno
))
188 for (bp
= bufhead
.b_prev
; bp
!= &bufhead
; bp
= bp
->b_prev
)
189 if ((bp
->b_flags
& B_INUSE
) == 0)
192 errexit("deadlocked buffer pool");
193 getblk(bp
, blkno
, size
);
198 bp
->b_prev
->b_next
= bp
->b_next
;
199 bp
->b_next
->b_prev
= bp
->b_prev
;
200 bp
->b_prev
= &bufhead
;
201 bp
->b_next
= bufhead
.b_next
;
202 bufhead
.b_next
->b_prev
= bp
;
204 bp
->b_flags
|= B_INUSE
;
209 getblk(struct bufarea
*bp
, daddr_t blk
, long size
)
213 dblk
= fsbtodb(&sblock
, blk
);
214 if (bp
->b_bno
!= dblk
) {
215 flush(fswritefd
, bp
);
216 bp
->b_errs
= bread(fsreadfd
, bp
->b_un
.b_buf
, dblk
, size
);
223 flush(int fd
, struct bufarea
*bp
)
230 pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n",
231 (bp
->b_errs
== bp
->b_size
/ dev_bsize
) ? "" : "PARTIALLY ",
232 (long long)bp
->b_bno
);
235 bwrite(fd
, bp
->b_un
.b_buf
, bp
->b_bno
, (long)bp
->b_size
);
238 for (i
= 0; i
< sblock
.e2fs_ngdb
; i
++) {
239 bwrite(fswritefd
, (char *)
240 &sblock
.e2fs_gd
[i
* sblock
.e2fs_bsize
/ sizeof(struct ext2_gd
)],
241 fsbtodb(&sblock
, ((sblock
.e2fs_bsize
>1024)?0:1)+i
+1),
247 rwerror(const char *mesg
, daddr_t blk
)
252 pfatal("CANNOT %s: BLK %lld", mesg
, (long long)blk
);
253 if (reply("CONTINUE") == 0)
254 errexit("Program terminated");
258 ckfini(int markclean
)
260 struct bufarea
*bp
, *nbp
;
264 (void)close(fsreadfd
);
267 flush(fswritefd
, &sblk
);
268 if (havesb
&& sblk
.b_bno
!= SBOFF
/ dev_bsize
&&
269 !preen
&& reply("UPDATE STANDARD SUPERBLOCKS")) {
270 sblk
.b_bno
= SBOFF
/ dev_bsize
;
272 flush(fswritefd
, &sblk
);
275 flush(fswritefd
, &asblk
);
277 for (bp
= bufhead
.b_prev
; bp
&& bp
!= &bufhead
; bp
= nbp
) {
279 flush(fswritefd
, bp
);
281 free(bp
->b_un
.b_buf
);
284 if (bufhead
.b_size
!= cnt
)
285 errexit("Panic: lost %d buffers", bufhead
.b_size
- cnt
);
286 pbp
= pdirbp
= (struct bufarea
*)0;
287 if (markclean
&& (sblock
.e2fs
.e2fs_state
& E2FS_ISCLEAN
) == 0) {
289 * Mark the file system as clean, and sync the superblock.
292 pwarn("MARKING FILE SYSTEM CLEAN\n");
293 else if (!reply("MARK FILE SYSTEM CLEAN"))
296 sblock
.e2fs
.e2fs_state
= E2FS_ISCLEAN
;
298 flush(fswritefd
, &sblk
);
302 printf("cache missed %ld of %ld (%d%%)\n", diskreads
,
303 totalreads
, (int)(diskreads
* 100 / totalreads
));
304 (void)close(fsreadfd
);
305 (void)close(fswritefd
);
309 bread(int fd
, char *buf
, daddr_t blk
, long size
)
322 if (lseek(fd
, offset
, 0) < 0)
323 rwerror("SEEK", blk
);
325 if (lseek64(fd
, offset
, 0, NULL
) < 0)
326 rwerror("SEEK", blk
);
328 else if (read(fd
, buf
, (int)size
) == size
)
330 rwerror("READ", blk
);
332 if (lseek(fd
, offset
, 0) < 0)
333 rwerror("SEEK", blk
);
335 if (lseek64(fd
, offset
, 0, NULL
) < 0)
336 rwerror("SEEK", blk
);
339 memset(buf
, 0, (size_t)size
);
340 printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
341 for (cp
= buf
, i
= 0; i
< size
; i
+= secsize
, cp
+= secsize
) {
342 if (read(fd
, cp
, (int)secsize
) != secsize
) {
343 (void)lseek(fd
, offset
+ i
+ secsize
, 0);
344 if (secsize
!= dev_bsize
&& dev_bsize
!= 1)
345 printf(" %lld (%lld),",
346 (long long)((blk
*dev_bsize
+ i
) / secsize
),
347 (long long)(blk
+ i
/ dev_bsize
));
349 printf(" %lld,", (long long)(blk
+
359 bwrite(int fd
, char *buf
, daddr_t blk
, long size
)
374 if (lseek(fd
, offset
, 0) < 0)
375 rwerror("SEEK", blk
);
377 if (lseek64(fd
, offset
, 0, NULL
) < 0)
378 rwerror("SEEK", blk
);
380 else if (write(fd
, buf
, (int)size
) == size
) {
384 rwerror("WRITE", blk
);
386 if (lseek(fd
, offset
, 0) < 0)
387 rwerror("SEEK", blk
);
389 if (lseek64(fd
, offset
, 0, NULL
) < 0)
390 rwerror("SEEK", blk
);
392 printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
393 for (cp
= buf
, i
= 0; i
< size
; i
+= dev_bsize
, cp
+= dev_bsize
)
394 if (write(fd
, cp
, (int)dev_bsize
) != dev_bsize
) {
395 (void)lseek(fd
, offset
+ i
+ dev_bsize
, 0);
396 printf(" %lld,", (long long)(blk
+ i
/ dev_bsize
));
403 * allocate a data block
410 for (i
= 0; i
< maxfsblock
- 1; i
++) {
421 * Free a previously allocated block
424 freeblk(daddr_t blkno
)
426 struct inodesc idesc
;
428 idesc
.id_blkno
= blkno
;
429 idesc
.id_numfrags
= 1;
430 (void)pass4check(&idesc
);
437 getpathname(char *namebuf
, size_t namebuflen
, ino_t curdir
, ino_t ino
)
441 struct inodesc idesc
;
444 if (curdir
== ino
&& ino
== EXT2_ROOTINO
) {
445 (void)strlcpy(namebuf
, "/", namebuflen
);
449 (statemap
[curdir
] != DSTATE
&& statemap
[curdir
] != DFOUND
)) {
450 (void)strlcpy(namebuf
, "?", namebuflen
);
454 memset(&idesc
, 0, sizeof(struct inodesc
));
455 idesc
.id_type
= DATA
;
456 idesc
.id_fix
= IGNORE
;
457 cp
= &namebuf
[MAXPATHLEN
- 1];
460 idesc
.id_parent
= curdir
;
463 while (ino
!= EXT2_ROOTINO
) {
464 idesc
.id_number
= ino
;
465 idesc
.id_func
= findino
;
466 idesc
.id_name
= "..";
467 if ((ckinode(ginode(ino
), &idesc
) & FOUND
) == 0)
470 idesc
.id_number
= idesc
.id_parent
;
471 idesc
.id_parent
= ino
;
472 idesc
.id_func
= findname
;
473 idesc
.id_name
= namebuf
;
474 if ((ckinode(ginode(idesc
.id_number
), &idesc
)&FOUND
) == 0)
476 len
= strlen(namebuf
);
478 memcpy(cp
, namebuf
, (size_t)len
);
480 if (cp
< &namebuf
[EXT2FS_MAXNAMLEN
])
482 ino
= idesc
.id_number
;
485 if (ino
!= EXT2_ROOTINO
)
487 memcpy(namebuf
, cp
, (size_t)(&namebuf
[MAXPATHLEN
] - cp
));
491 * determine whether an inode should be fixed.
494 dofix(struct inodesc
*idesc
, const char *msg
)
497 switch (idesc
->id_fix
) {
500 if (idesc
->id_type
== DATA
)
501 direrror(idesc
->id_number
, msg
);
505 printf(" (SALVAGED)\n");
509 if (reply("SALVAGE") == 0) {
510 idesc
->id_fix
= NOFIX
;
524 errexit("UNKNOWN INODESC FIX MODE %d", idesc
->id_fix
);