2 * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
5 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
6 /* All Rights Reserved */
9 * Copyright (c) 1980, 1986, 1990 The Regents of the University of California.
10 * All rights reserved.
12 * Redistribution and use in source and binary forms are permitted
13 * provided that: (1) source distributions retain this entire copyright
14 * notice and comment, and (2) distributions including binaries display
15 * the following acknowledgement: ``This product includes software
16 * developed by the University of California, Berkeley and its contributors''
17 * in the documentation or other materials provided with the distribution
18 * and in all advertising materials mentioning features or use of this
19 * software. Neither the name of the University nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
39 #include <sys/param.h>
40 #include <sys/types.h>
41 #include <sys/mntent.h>
42 #include <sys/filio.h>
43 #include <sys/vnode.h>
44 #include <sys/mnttab.h>
45 #include <sys/types.h>
47 #include <sys/vfstab.h>
48 #include <sys/sysmacros.h>
49 #include <sys/fs/udf_volume.h>
51 #include <sys/lockfs.h>
54 extern int32_t verifytag(struct tag
*, uint32_t, struct tag
*, int);
55 extern char *tagerrs
[];
56 extern void maketag(struct tag
*, struct tag
*);
57 extern char *hasvfsopt(struct vfstab
*, char *);
58 static struct bufarea
*getdatablk(daddr_t
, long);
59 static struct bufarea
*getblk(struct bufarea
*, daddr_t
, long);
61 void flush(int32_t, struct bufarea
*);
62 int32_t bread(int32_t, char *, daddr_t
, long);
63 void bwrite(int, char *, daddr_t
, long);
64 static int32_t getaline(FILE *, char *, int32_t);
65 void errexit(char *, ...) __NORETURN
;
66 static long diskreads
, totalreads
; /* Disk cache statistics */
68 extern unsigned int largefile_count
;
71 * An unexpected inconsistency occured.
72 * Die if preening, otherwise just print message and continue.
76 pfatal(char *fmt
, ...)
81 (void) printf("%s: ", devname
);
82 (void) vprintf(fmt
, args
);
85 gettext("%s: UNEXPECTED INCONSISTENCY; RUN fsck "
86 "MANUALLY.\n"), devname
);
90 (void) vprintf(fmt
, args
);
95 * Pwarn just prints a message when not preening,
96 * or a warning (preceded by filename) when preening.
100 pwarn(char *fmt
, ...)
105 (void) printf("%s: ", devname
);
106 (void) vprintf(fmt
, args
);
113 errexit(char *fmt
, ...)
117 (void) vprintf(fmt
, args
);
123 markbusy(daddr_t block
, long count
)
127 count
= roundup(count
, secsize
) / secsize
;
128 for (i
= 0; i
< count
; i
++, block
++) {
129 if ((unsigned)block
> part_len
) {
130 pwarn(gettext("Block %lx out of range\n"), block
);
134 pwarn(gettext("Dup block %lx\n"), block
);
145 int i
, startfree
, endfree
;
148 for (i
= 0; i
< part_len
; i
++) {
153 } else if (startfree
>= 0) {
154 (void) printf("free: %x-%x\n", startfree
, endfree
- 1);
158 if (startfree
>= 0) {
159 (void) printf("free: %x-%x\n", startfree
, endfree
);
164 getfilentry(uint32_t block
, int len
)
167 struct file_entry
*fp
;
171 (void) printf(gettext("File entry at %x is too long "
172 "(%d bytes)\n"), block
, len
);
175 bp
= getdatablk((daddr_t
)(block
+ part_start
), fsbsize
);
177 bp
->b_flags
&= ~B_INUSE
;
181 fp
= (struct file_entry
*)bp
->b_un
.b_buf
;
182 err
= verifytag(&fp
->fe_tag
, block
, &fp
->fe_tag
, UD_FILE_ENTRY
);
184 (void) printf(gettext("Tag error %s or bad file entry, "
185 "tag=%d\n"), tagerrs
[err
], fp
->fe_tag
.tag_id
);
186 bp
->b_flags
&= ~B_INUSE
;
193 putfilentry(struct bufarea
*bp
)
195 struct file_entry
*fp
;
198 fp
= (struct file_entry
*)bp
->b_un
.b_buf
;
199 maketag(&fp
->fe_tag
, &fp
->fe_tag
);
204 reply(char *question
)
209 pfatal(gettext("INTERNAL ERROR: GOT TO reply()"));
210 (void) printf("\n%s? ", question
);
211 if (nflag
|| fswritefd
< 0) {
212 (void) printf(gettext(" no\n\n"));
213 iscorrupt
= 1; /* known to be corrupt */
217 (void) printf(gettext(" yes\n\n"));
220 if (getaline(stdin
, line
, sizeof (line
)) == EOF
)
223 if (line
[0] == 'y' || line
[0] == 'Y')
226 iscorrupt
= 1; /* known to be corrupt */
232 getaline(FILE *fp
, char *loc
, int32_t maxlen
)
235 register char *p
, *lastloc
;
238 lastloc
= &p
[maxlen
-1];
239 while ((n
= getc(fp
)) != '\n') {
242 if (!isspace(n
) && p
< lastloc
)
249 * Malloc buffers and set up cache.
254 register struct bufarea
*bp
;
258 bufp
= malloc((unsigned int)fsbsize
);
260 errexit(gettext("cannot allocate buffer pool\n"));
261 bufhead
.b_next
= bufhead
.b_prev
= &bufhead
;
262 bufcnt
= MAXBUFSPACE
/ fsbsize
;
263 if (bufcnt
< MINBUFS
)
265 for (i
= 0; i
< bufcnt
; i
++) {
266 bp
= (struct bufarea
*)malloc(sizeof (struct bufarea
));
267 bufp
= malloc((unsigned int)fsbsize
);
268 if (bp
== NULL
|| bufp
== NULL
) {
271 errexit(gettext("cannot allocate buffer pool\n"));
273 bp
->b_un
.b_buf
= bufp
;
274 bp
->b_prev
= &bufhead
;
275 bp
->b_next
= bufhead
.b_next
;
276 bufhead
.b_next
->b_prev
= bp
;
280 bufhead
.b_size
= i
; /* save number of buffers */
285 * Manage a cache of directory blocks.
287 static struct bufarea
*
288 getdatablk(daddr_t blkno
, long size
)
290 register struct bufarea
*bp
;
292 for (bp
= bufhead
.b_next
; bp
!= &bufhead
; bp
= bp
->b_next
)
293 if (bp
->b_bno
== fsbtodb(blkno
))
295 for (bp
= bufhead
.b_prev
; bp
!= &bufhead
; bp
= bp
->b_prev
)
296 if ((bp
->b_flags
& B_INUSE
) == 0)
299 errexit(gettext("deadlocked buffer pool\n"));
300 (void) getblk(bp
, blkno
, size
);
304 bp
->b_prev
->b_next
= bp
->b_next
;
305 bp
->b_next
->b_prev
= bp
->b_prev
;
306 bp
->b_prev
= &bufhead
;
307 bp
->b_next
= bufhead
.b_next
;
308 bufhead
.b_next
->b_prev
= bp
;
310 bp
->b_flags
|= B_INUSE
;
314 static struct bufarea
*
315 getblk(struct bufarea
*bp
, daddr_t blk
, long size
)
320 if (bp
->b_bno
== dblk
)
322 flush(fswritefd
, bp
);
324 bp
->b_errs
= bread(fsreadfd
, bp
->b_un
.b_buf
, dblk
, size
);
331 flush(int32_t fd
, struct bufarea
*bp
)
336 pfatal(gettext("WRITING ZERO'ED BLOCK %d TO DISK\n"),
340 bwrite(fd
, bp
->b_un
.b_buf
, bp
->b_bno
, (long)bp
->b_size
);
344 rwerror(char *mesg
, daddr_t blk
)
349 pfatal(gettext("CANNOT %s: BLK %ld"), mesg
, blk
);
350 if (reply(gettext("CONTINUE")) == 0)
351 errexit(gettext("Program terminated\n"));
357 struct bufarea
*bp
, *nbp
;
360 for (bp
= bufhead
.b_prev
; bp
&& bp
!= &bufhead
; bp
= nbp
) {
362 flush(fswritefd
, bp
);
364 free(bp
->b_un
.b_buf
);
368 if (bufhead
.b_size
!= cnt
)
369 errexit(gettext("Panic: lost %d buffers\n"),
370 bufhead
.b_size
- cnt
);
372 (void) printf("cache missed %ld of %ld (%ld%%)\n",
373 diskreads
, totalreads
,
374 totalreads
? diskreads
* 100 / totalreads
: 0);
375 (void) close(fsreadfd
);
376 (void) close(fswritefd
);
380 bread(int fd
, char *buf
, daddr_t blk
, long size
)
384 offset_t offset
= ldbtob(blk
);
387 if (llseek(fd
, offset
, 0) < 0)
388 rwerror(gettext("SEEK"), blk
);
389 else if (read(fd
, buf
, (int)size
) == size
)
391 rwerror(gettext("READ"), blk
);
392 if (llseek(fd
, offset
, 0) < 0)
393 rwerror(gettext("SEEK"), blk
);
395 bzero(buf
, (int)size
);
396 pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE READ:"));
397 for (cp
= buf
, i
= 0; i
< btodb(size
); i
++, cp
+= DEV_BSIZE
) {
398 addr
= ldbtob(blk
+ i
);
399 if (llseek(fd
, addr
, SEEK_CUR
) < 0 ||
400 read(fd
, cp
, (int)secsize
) < 0) {
401 (void) printf(" %ld", blk
+ i
);
410 bwrite(int fd
, char *buf
, daddr_t blk
, long size
)
414 offset_t offset
= ldbtob(blk
);
419 if (llseek(fd
, offset
, 0) < 0)
420 rwerror(gettext("SEEK"), blk
);
421 else if (write(fd
, buf
, (int)size
) == size
) {
425 rwerror(gettext("WRITE"), blk
);
426 if (llseek(fd
, offset
, 0) < 0)
427 rwerror(gettext("SEEK"), blk
);
428 pwarn(gettext("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"));
429 for (cp
= buf
, i
= 0; i
< btodb(size
); i
++, cp
+= DEV_BSIZE
) {
431 addr
= ldbtob(blk
+ i
);
432 if (llseek(fd
, addr
, SEEK_CUR
) < 0 ||
433 (n
= write(fd
, cp
, DEV_BSIZE
)) < 0) {
434 (void) printf(" %ld", blk
+ i
);
451 * When preening, allow a single quit to signal
452 * a special exit after filesystem checks complete
453 * so that reboot sequence may be interrupted.
458 extern int returntosingle
;
460 (void) printf(gettext("returning to single-user after filesystem "
463 (void) signal(SIGQUIT
, SIG_DFL
);
467 * determine whether an inode should be fixed.
471 dofix(struct inodesc
*idesc
, char *msg
)
474 switch (idesc
->id_fix
) {
479 (void) printf(gettext(" (SALVAGED)\n"));
483 if (reply(gettext("SALVAGE")) == 0) {
484 idesc
->id_fix
= NOFIX
;
497 errexit(gettext("UNKNOWN INODESC FIX MODE %d\n"),
504 * Check to see if unraw version of name is already mounted.
505 * Since we do not believe /etc/mnttab, we stat the mount point
506 * to see if it is really looks mounted.
514 struct stat device_stat
, mount_stat
;
515 char *blkname
, *unrawname();
518 mnttab
= fopen(MNTTAB
, "r");
519 if (mnttab
== NULL
) {
520 (void) printf(gettext("can't open %s\n"), MNTTAB
);
523 blkname
= unrawname(name
);
524 while ((getmntent(mnttab
, &mnt
)) == 0) {
525 if (strcmp(mnt
.mnt_fstype
, MNTTYPE_UDFS
) != 0) {
528 if (strcmp(blkname
, mnt
.mnt_special
) == 0) {
529 err
= stat(mnt
.mnt_mountp
, &mount_stat
);
530 err
|= stat(mnt
.mnt_special
, &device_stat
);
533 if (device_stat
.st_rdev
== mount_stat
.st_dev
) {
534 (void) strncpy(mnt
.mnt_mountp
, mountpoint
,
535 sizeof (mountpoint
));
536 if (hasmntopt(&mnt
, MNTOPT_RO
) != 0)
537 found
= 2; /* mounted as RO */
539 found
= 1; /* mounted as R/W */
544 (void) fclose(mnttab
);
549 * Check to see if name corresponds to an entry in vfstab, and that the entry
550 * does not have option ro.
556 struct vfstab vfsbuf
;
558 char *blkname
, *unrawname();
560 vfstab
= fopen(VFSTAB
, "r");
561 if (vfstab
== NULL
) {
562 (void) printf(gettext("can't open %s\n"), VFSTAB
);
565 blkname
= unrawname(name
);
566 if ((getvfsspec(vfstab
, &vfsbuf
, blkname
) == 0) &&
567 (vfsbuf
.vfs_fstype
!= NULL
) &&
568 (strcmp(vfsbuf
.vfs_fstype
, MNTTYPE_UDFS
) == 0) &&
569 (hasvfsopt(&vfsbuf
, MNTOPT_RO
))) {
572 (void) fclose(vfstab
);
577 * print out clean info
584 switch (lvintp
->lvid_int_type
) {
587 s
= gettext("clean");
591 s
= gettext("active");
595 s
= gettext("unknown");
599 pwarn(gettext("is %s.\n"), s
);
601 (void) printf("** %s is %s.\n", devname
, s
);