1 /* Hacks for version 1.6 */
3 #define INODES_PER_BLOCK V2_INODES_PER_BLOCK(block_size)
4 #define INODE_SIZE ((int) V2_INODE_SIZE)
5 #define WORDS_PER_BLOCK (block_size / (int) sizeof(bitchunk_t))
6 #define MAX_ZONES (V2_NR_DZONES+V2_INDIRECTS(block_size)+(long)V2_INDIRECTS(block_size)*V2_INDIRECTS(block_size))
7 #define NR_DZONE_NUM V2_NR_DZONES
8 #define NR_INDIRECTS V2_INDIRECTS(block_size)
9 #define NR_ZONE_NUMS V2_NR_TZONES
10 #define ZONE_NUM_SIZE V2_ZONE_NUM_SIZE
12 #define block_nr block_t
13 #define d_inode d2_inode
14 #define d_inum mfs_d_ino
15 #define dir_struct struct direct
16 #define i_mode d2_mode
17 #define i_nlinks d2_nlinks
18 #define i_size d2_size
19 #define i_zone d2_zone
20 #define zone_nr zone_t
22 /* fsck - file system checker Author: Robbert van Renesse */
24 /* Modified by Norbert Schlenker
25 * Removed vestiges of standalone/DOS versions:
26 * - various unused variables and buffers removed
27 * - now uses library functions rather than private internal routines
28 * - bytewise structure copies replaced by structure assignment
29 * - fixed one bug with 14 character file names
30 * - other small tweaks for speed
32 * Modified by Lars Fredriksen at the request of Andy Tanenbaum, 90-03-10.
33 * Removed -m option, by which fsck could be told to make a file
34 * system on a 360K floppy. The code had limited utility, was buggy,
35 * and failed due to a bug in the ACK C compiler. Use mkfs instead!
38 #include <sys/types.h>
46 #include <minix/config.h>
47 #include <minix/const.h>
48 #include <minix/type.h>
49 #include <minix/ipc.h>
50 #include "mfs/const.h"
51 #include "mfs/inode.h"
53 #include "mfs/mfsdir.h"
54 #include <minix/fslib.h>
59 #include "exitvalues.h"
63 unsigned int fs_version
= 2, block_size
= 0;
65 #define BITSHIFT 5 /* = log2(#bits(int)) */
67 #define MAXPRINT 80 /* max. number of error lines in chkmap */
68 #define CINDIR 128 /* number of indirect zno's read at a time */
69 #define CDIRECT 1 /* number of dir entries read at a time */
71 /* Macros for handling bitmaps. Now bit_t is long, these are bulky and the
72 * type demotions produce a lot of lint. The explicit demotion in POWEROFBIT
73 * is for efficiency and assumes 2's complement ints. Lint should be clever
74 * enough not to warn about it since BITMASK is small, but isn't. (It would
75 * be easier to get right if bit_t was was unsigned (long) since then there
76 * would be no danger from wierd sign representations. Lint doesn't know
77 * we only use non-negative bit numbers.) There will usually be an implicit
78 * demotion when WORDOFBIT is used as an array index. This should be safe
79 * since memory for bitmaps will run out first.
81 #define BITMASK ((1 << BITSHIFT) - 1)
82 #define WORDOFBIT(b) ((b) >> BITSHIFT)
83 #define POWEROFBIT(b) (1 << ((int) (b) & BITMASK))
84 #define setbit(w, b) (w[WORDOFBIT(b)] |= POWEROFBIT(b))
85 #define clrbit(w, b) (w[WORDOFBIT(b)] &= ~POWEROFBIT(b))
86 #define bitset(w, b) (w[WORDOFBIT(b)] & POWEROFBIT(b))
88 #define ZONE_CT 360 /* default zones (when making file system) */
89 #define INODE_CT 95 /* default inodes (when making file system) */
91 #include "mfs/super.h"
92 static struct super_block sb
;
94 #define STICKY_BIT 01000 /* not defined anywhere else */
96 /* Ztob gives the block address of a zone
97 * btoa64 gives the byte address of a block
99 #define ztob(z) ((block_nr) (z) << sb.s_log_zone_size)
100 #define btoa64(b) ((u64_t)(b) * block_size)
101 #define SCALE ((int) ztob(1)) /* # blocks in a zone */
102 #define FIRST ((zone_nr) sb.s_firstdatazone) /* as the name says */
104 /* # blocks of each type */
105 #define N_IMAP (sb.s_imap_blocks)
106 #define N_ZMAP (sb.s_zmap_blocks)
107 #define N_ILIST ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
108 #define N_DATA (sb.s_zones - FIRST)
110 /* Block address of each type */
111 #define OFFSET_SUPER_BLOCK SUPER_BLOCK_BYTES
113 #define BLK_ZMAP (BLK_IMAP + N_IMAP)
114 #define BLK_ILIST (BLK_ZMAP + N_ZMAP)
115 #define BLK_FIRST ztob(FIRST)
116 #define ZONE_SIZE ((int) ztob(block_size))
117 #define NLEVEL (NR_ZONE_NUMS - NR_DZONE_NUM + 1)
119 /* Byte address of a zone */
120 #define INDCHUNK ((int) (CINDIR * ZONE_NUM_SIZE))
121 #define DIRCHUNK ((int) (CDIRECT * DIR_ENTRY_SIZE))
123 char *prog
, *fsck_device
; /* program name (fsck), device name */
124 int firstcnterr
; /* is this the first inode ref cnt error? */
125 bitchunk_t
*imap
, *spec_imap
; /* inode bit maps */
126 bitchunk_t
*zmap
, *spec_zmap
; /* zone bit maps */
127 bitchunk_t
*dirmap
; /* directory (inode) bit map */
128 char *rwbuf
; /* one block buffer cache */
129 block_nr thisblk
; /* block in buffer cache */
130 char *nullbuf
; /* null buffer */
131 nlink_t
*count
; /* inode count */
132 int changed
; /* has the diskette been written to? */
135 struct stack
*st_next
;
139 int dev
; /* file descriptor of the device */
144 /* Counters for each type of inode/zone. */
145 int nfreeinode
, nregular
, ndirectory
, nblkspec
, ncharspec
, nbadinode
;
146 int nsock
, npipe
, nsyml
, ztype
[NLEVEL
];
149 int repair
, notrepaired
= 0, automatic
, listing
, listsuper
; /* flags */
150 int preen
= 0, markdirty
= 0;
151 int firstlist
; /* has the listing header been printed? */
152 unsigned part_offset
; /* sector offset for this partition */
153 char answer
[] = "Answer questions with y or n. Then hit RETURN";
155 int main(int argc
, char **argv
);
159 int yes(char *question
);
161 int input(char *buf
, int size
);
162 char *alloc(unsigned nelem
, unsigned elsize
);
163 void printname(char *s
);
164 void printrec(struct stack
*sp
);
165 void printpath(int mode
, int nlcr
);
168 void devio(block_nr bno
, int dir
);
169 void devread(long block
, long offset
, char *buf
, int size
);
170 void devwrite(long block
, long offset
, char *buf
, int size
);
171 void pr(char *fmt
, int cnt
, char *s
, char *p
);
172 void lpr(char *fmt
, long cnt
, char *s
, char *p
);
173 bit_nr
getnumber(char *s
);
174 char **getlist(char ***argv
, char *type
);
178 void rw_super(int mode
);
180 void lsi(char **clist
);
181 bitchunk_t
*allocbitmap(int nblk
);
182 void loadbitmap(bitchunk_t
*bitmap
, block_nr bno
, int nblk
);
183 void dumpbitmap(bitchunk_t
*bitmap
, block_nr bno
, int nblk
);
184 void fillbitmap(bitchunk_t
*bitmap
, bit_nr lwb
, bit_nr upb
, char
186 void freebitmap(bitchunk_t
*p
);
187 void getbitmaps(void);
188 void putbitmaps(void);
189 void chkword(unsigned w1
, unsigned w2
, bit_nr bit
, char *type
, int *n
,
191 void chkmap(bitchunk_t
*cmap
, bitchunk_t
*dmap
, bit_nr bit
, block_nr
192 blkno
, int nblk
, char *type
);
195 void counterror(ino_t ino
);
197 void freecount(void);
198 void printperm(mode_t mode
, int shift
, int special
, int overlay
);
199 void list(ino_t ino
, d_inode
*ip
);
200 int Remove(dir_struct
*dp
);
201 void make_printable_name(char *dst
, char *src
, int n
);
202 int chkdots(ino_t ino
, off_t pos
, dir_struct
*dp
, ino_t exp
);
203 int chkname(ino_t ino
, dir_struct
*dp
);
204 int chkentry(ino_t ino
, off_t pos
, dir_struct
*dp
);
205 int chkdirzone(ino_t ino
, d_inode
*ip
, off_t pos
, zone_nr zno
);
206 int chksymlinkzone(ino_t ino
, d_inode
*ip
, off_t pos
, zone_nr zno
);
207 void errzone(char *mess
, zone_nr zno
, int level
, off_t pos
);
208 int markzone(zone_nr zno
, int level
, off_t pos
);
209 int chkindzone(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr zno
, int
211 off_t
jump(int level
);
212 int zonechk(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr zno
, int level
);
213 int chkzones(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr
*zlist
, int
215 int chkfile(ino_t ino
, d_inode
*ip
);
216 int chkdirectory(ino_t ino
, d_inode
*ip
);
217 int chklink(ino_t ino
, d_inode
*ip
);
218 int chkspecial(ino_t ino
, d_inode
*ip
);
219 int chkmode(ino_t ino
, d_inode
*ip
);
220 int chkinode(ino_t ino
, d_inode
*ip
);
221 int descendtree(dir_struct
*dp
);
223 void printtotal(void);
224 void chkdev(char *f
, char **clist
, char **ilist
, char **zlist
);
226 /* Initialize the variables used by this program. */
231 nregular
= ndirectory
= nblkspec
= ncharspec
=
232 nbadinode
= nsock
= npipe
= nsyml
= 0;
233 for (level
= 0; level
< NLEVEL
; level
++) ztype
[level
] = 0;
240 /* Print the string `s' and exit. */
244 printf("%s\nfatal\n", s
);
245 exit(FSCK_EXIT_CHECK_FAILED
);
248 /* Test for end of line. */
252 return(c
== EOF
|| c
== '\n' || c
== '\r');
255 /* Ask a question and get the answer unless automatic is set. */
259 register int c
, answerchar
;
267 printf("%s? ", question
);
268 if(!note
) { printf("(y=yes, n=no, q=quit, A=for yes to all) "); note
= 1; }
274 if ((c
= answerchar
= getchar()) == 'q' || c
== 'Q') exit(FSCK_EXIT_CHECK_FAILED
);
275 if(c
== 'A') { automatic
= 1; c
= 'y'; }
276 while (!eoln(c
)) c
= getchar();
277 yes
= !(answerchar
== 'n' || answerchar
== 'N');
278 if(!yes
) notrepaired
= 1;
282 /* Convert string to integer. Representation is octal. */
288 while ('0' <= *s
&& *s
< '8') {
295 /* If repairing the file system, print a prompt and get a string from user. */
300 register char *p
= buf
;
315 while (!eoln(getchar()));
321 /* Allocate some memory and zero it. */
322 char *alloc(nelem
, elsize
)
323 unsigned nelem
, elsize
;
327 if ((p
= (char *)malloc((size_t)nelem
* elsize
)) == 0) {
328 fprintf(stderr
, "Tried to allocate %dkB\n",
330 fatal("out of memory");
332 memset((void *) p
, 0, (size_t)nelem
* elsize
);
336 /* Print the name in a directory entry. */
340 register int n
= MFS_NAME_MAX
;
344 if ((c
= *s
) == 0) break;
345 if (!isprint(c
)) c
= '?';
351 /* Print the pathname given by a linked list pointed to by `sp'. The
352 * names are in reverse order.
354 void printrec(struct stack
*sp
)
356 if (sp
->st_next
!= 0) {
357 printrec(sp
->st_next
);
359 printname(sp
->st_dir
->mfs_d_name
);
363 /* Print the current pathname. */
364 void printpath(mode
, nlcr
)
368 if (ftop
->st_next
== 0)
374 printf(" (ino = %u, ", ftop
->st_dir
->d_inum
);
377 printf(" (ino = %u)", ftop
->st_dir
->d_inum
);
380 if (nlcr
) printf("\n");
383 /* Open the device. */
386 if ((dev
= open(fsck_device
,
387 (repair
|| markdirty
) ? O_RDWR
: O_RDONLY
)) < 0) {
389 fatal("couldn't open device to fsck");
393 /* Close the device. */
396 if (close(dev
) != 0) {
402 /* Read or write a block. */
409 if(!block_size
) fatal("devio() with unknown block size");
410 if (dir
== READING
&& bno
== thisblk
) return;
414 printf("%s at block %5d\n", dir
== READING
? "reading " : "writing", bno
);
416 r
= lseek(dev
, btoa64(bno
), SEEK_SET
);
418 fatal("lseek failed");
419 if (dir
== READING
) {
420 if (read(dev
, rwbuf
, block_size
) == block_size
)
423 if (write(dev
, rwbuf
, block_size
) == block_size
)
427 printf("%s: can't %s block %ld (error = 0x%x)\n", prog
,
428 dir
== READING
? "read" : "write", (long) bno
, errno
);
429 if (dir
== READING
) {
430 printf("Continuing with a zero-filled block.\n");
431 memset(rwbuf
, 0, block_size
);
437 /* Read `size' bytes from the disk starting at block 'block' and
440 void devread(block
, offset
, buf
, size
)
446 if(!block_size
) fatal("devread() with unknown block size");
447 if (offset
>= block_size
)
449 block
+= offset
/block_size
;
450 offset
%= block_size
;
452 devio(block
, READING
);
453 memmove(buf
, &rwbuf
[offset
], size
);
456 /* Write `size' bytes to the disk starting at block 'block' and
459 void devwrite(block
, offset
, buf
, size
)
465 if(!block_size
) fatal("devwrite() with unknown block size");
466 if (!repair
) fatal("internal error (devwrite)");
467 if (offset
>= block_size
)
469 block
+= offset
/block_size
;
470 offset
%= block_size
;
472 if (size
!= block_size
) devio(block
, READING
);
473 memmove(&rwbuf
[offset
], buf
, size
);
474 devio(block
, WRITING
);
478 /* Print a string with either a singular or a plural pronoun. */
479 void pr(fmt
, cnt
, s
, p
)
483 printf(fmt
, cnt
, cnt
== 1 ? s
: p
);
486 /* Same as above, but with a long argument */
487 void lpr(fmt
, cnt
, s
, p
)
491 printf(fmt
, cnt
, cnt
== 1 ? s
: p
);
494 /* Convert string to number. */
498 register bit_nr n
= 0;
503 n
= (n
<< 1) + (n
<< 3) + *s
++ - '0';
504 return (*s
== '\0') ? n
: NO_BIT
;
507 /* See if the list pointed to by `argv' contains numbers. */
508 char **getlist(argv
, type
)
511 register char **list
= *argv
;
512 register int empty
= 1;
514 while (getnumber(**argv
) != NO_BIT
) {
519 printf("warning: no %s numbers given\n", type
);
525 /* Make a listing of the super block. If `repair' is set, ask the user
533 /* Most of the following atol's enrage lint, for good reason. */
534 printf("ninodes = %u", sb
.s_ninodes
);
535 if (input(buf
, 80)) sb
.s_ninodes
= atol(buf
);
536 printf("nzones = %d", sb
.s_zones
);
537 if (input(buf
, 80)) sb
.s_zones
= atol(buf
);
538 printf("imap_blocks = %u", sb
.s_imap_blocks
);
539 if (input(buf
, 80)) sb
.s_imap_blocks
= atol(buf
);
540 printf("zmap_blocks = %u", sb
.s_zmap_blocks
);
541 if (input(buf
, 80)) sb
.s_zmap_blocks
= atol(buf
);
542 printf("firstdatazone = %u", sb
.s_firstdatazone_old
);
543 if (input(buf
, 80)) sb
.s_firstdatazone_old
= atol(buf
);
544 printf("log_zone_size = %u", sb
.s_log_zone_size
);
545 if (input(buf
, 80)) sb
.s_log_zone_size
= atol(buf
);
546 printf("maxsize = %d", sb
.s_max_size
);
547 if (input(buf
, 80)) sb
.s_max_size
= atol(buf
);
548 printf("block size = %d", sb
.s_block_size
);
549 if (input(buf
, 80)) sb
.s_block_size
= atol(buf
);
551 devwrite(0, OFFSET_SUPER_BLOCK
, (char *) &sb
, sizeof(sb
));
555 if(sb
.s_flags
& MFSFLAG_CLEAN
) printf("CLEAN "); else printf("DIRTY ");
557 } while (yes("Do you want to try again"));
558 if (repair
) exit(FSCK_EXIT_OK
);
561 /* Get the super block from either disk or user. Do some initial checks. */
562 void rw_super(int put
)
564 if(lseek(dev
, OFFSET_SUPER_BLOCK
, SEEK_SET
) < 0) {
566 fatal("couldn't seek to super block.");
568 if(put
== SUPER_PUT
) {
569 if(write(dev
, &sb
, sizeof(sb
)) != sizeof(sb
)) {
570 fatal("couldn't write super block.");
574 if(read(dev
, &sb
, sizeof(sb
)) != sizeof(sb
)) {
575 fatal("couldn't read super block.");
577 if (listsuper
) lsuper();
578 if (sb
.s_magic
== SUPER_MAGIC
) fatal("Cannot handle V1 file systems");
579 if (sb
.s_magic
== SUPER_V2
) {
581 block_size
= /* STATIC_BLOCK_SIZE */ 8192;
582 } else if(sb
.s_magic
== SUPER_V3
) {
584 block_size
= sb
.s_block_size
;
586 fatal("bad magic number in super block");
588 if (sb
.s_ninodes
<= 0) fatal("no inodes");
589 if (sb
.s_zones
<= 0) fatal("no zones");
590 if (sb
.s_imap_blocks
<= 0) fatal("no imap");
591 if (sb
.s_zmap_blocks
<= 0) fatal("no zmap");
592 if (sb
.s_firstdatazone
!= 0 && sb
.s_firstdatazone
<= 4)
593 fatal("first data zone too small");
594 if (sb
.s_log_zone_size
< 0) fatal("zone size < block size");
595 if (sb
.s_max_size
<= 0) {
596 printf("warning: invalid max file size %d\n", sb
.s_max_size
);
597 sb
.s_max_size
= LONG_MAX
;
601 /* Check the super block for reasonable contents. */
605 register off_t maxsize
;
607 n
= bitmapsize((bit_t
) sb
.s_ninodes
+ 1, block_size
);
608 if (sb
.s_magic
!= SUPER_V2
&& sb
.s_magic
!= SUPER_V3
)
609 fatal("bad magic number in super block");
610 if (sb
.s_imap_blocks
< n
) {
611 printf("need %d bocks for inode bitmap; only have %d\n",
612 n
, sb
.s_imap_blocks
);
613 fatal("too few imap blocks");
615 if (sb
.s_imap_blocks
!= n
) {
616 pr("warning: expected %d imap_block%s", n
, "", "s");
617 printf(" instead of %d\n", sb
.s_imap_blocks
);
619 n
= bitmapsize((bit_t
) sb
.s_zones
, block_size
);
620 if (sb
.s_zmap_blocks
< n
) fatal("too few zmap blocks");
621 if (sb
.s_zmap_blocks
!= n
) {
622 pr("warning: expected %d zmap_block%s", n
, "", "s");
623 printf(" instead of %d\n", sb
.s_zmap_blocks
);
625 if (sb
.s_log_zone_size
>= 8 * sizeof(block_nr
))
626 fatal("log_zone_size too large");
627 if (sb
.s_log_zone_size
> 8) printf("warning: large log_zone_size (%d)\n",
629 sb
.s_firstdatazone
= (BLK_ILIST
+ N_ILIST
+ SCALE
- 1) >> sb
.s_log_zone_size
;
630 if (sb
.s_firstdatazone_old
!= 0) {
631 if (sb
.s_firstdatazone_old
>= sb
.s_zones
)
632 fatal("first data zone too large");
633 if (sb
.s_firstdatazone_old
< sb
.s_firstdatazone
)
634 fatal("first data zone too small");
635 if (sb
.s_firstdatazone_old
!= sb
.s_firstdatazone
) {
636 printf("warning: expected first data zone to be %u ",
638 printf("instead of %u\n", sb
.s_firstdatazone_old
);
639 sb
.s_firstdatazone
= sb
.s_firstdatazone_old
;
642 maxsize
= MAX_FILE_POS
;
643 if (((maxsize
- 1) >> sb
.s_log_zone_size
) / block_size
>= MAX_ZONES
)
644 maxsize
= ((long) MAX_ZONES
* block_size
) << sb
.s_log_zone_size
;
647 if (sb
.s_max_size
!= maxsize
) {
648 printf("warning: expected max size to be %lld ", maxsize
);
649 printf("instead of %d\n", sb
.s_max_size
);
652 if(sb
.s_flags
& MFSFLAG_MANDATORY_MASK
) {
653 fatal("unsupported feature bits - newer fsck needed");
657 int inoblock(int inn
)
659 return (int)(((u64_t
)(inn
- 1) * INODE_SIZE
) / block_size
) + BLK_ILIST
;
664 return (int)(((u64_t
)(inn
- 1) * INODE_SIZE
) % block_size
);
667 /* Make a listing of the inodes given by `clist'. If `repair' is set, ask
668 * the user for changes.
675 d_inode inode
, *ip
= &inode
;
678 if (clist
== 0) return;
679 while ((bit
= getnumber(*clist
++)) != NO_BIT
) {
680 setbit(spec_imap
, bit
);
683 devread(inoblock(ino
), inooff(ino
), (char *) ip
, INODE_SIZE
);
684 printf("inode %llu:\n", ino
);
685 printf(" mode = %6o", ip
->i_mode
);
686 if (input(buf
, 80)) ip
->i_mode
= atoo(buf
);
687 printf(" nlinks = %6u", ip
->i_nlinks
);
688 if (input(buf
, 80)) ip
->i_nlinks
= atol(buf
);
689 printf(" size = %6d", ip
->i_size
);
690 if (input(buf
, 80)) ip
->i_size
= atol(buf
);
691 if (yes("Write this back")) {
692 devwrite(inoblock(ino
), inooff(ino
), (char *) ip
,
696 } while (yes("Do you want to change it again"));
700 /* Allocate `nblk' blocks worth of bitmap. */
701 bitchunk_t
*allocbitmap(nblk
)
704 register bitchunk_t
*bitmap
;
706 bitmap
= (bitchunk_t
*) alloc((unsigned) nblk
, block_size
);
711 /* Load the bitmap starting at block `bno' from disk. */
712 void loadbitmap(bitmap
, bno
, nblk
)
718 register bitchunk_t
*p
;
721 for (i
= 0; i
< nblk
; i
++, bno
++, p
+= WORDS_PER_BLOCK
)
722 devread(bno
, 0, (char *) p
, block_size
);
726 /* Write the bitmap starting at block `bno' to disk. */
727 void dumpbitmap(bitmap
, bno
, nblk
)
733 register bitchunk_t
*p
= bitmap
;
735 for (i
= 0; i
< nblk
; i
++, bno
++, p
+= WORDS_PER_BLOCK
)
736 devwrite(bno
, 0, (char *) p
, block_size
);
739 /* Set the bits given by `list' in the bitmap. */
740 void fillbitmap(bitmap
, lwb
, upb
, list
)
747 if (list
== 0) return;
748 while ((bit
= getnumber(*list
++)) != NO_BIT
)
749 if (bit
< lwb
|| bit
>= upb
) {
750 if (bitmap
== spec_imap
)
751 printf("inode number %d ", bit
);
753 printf("zone number %d ", bit
);
754 printf("out of range (ignored)\n");
756 setbit(bitmap
, bit
- lwb
+ 1);
759 /* Deallocate the bitmap `p'. */
766 /* Get all the bitmaps used by this program. */
769 imap
= allocbitmap(N_IMAP
);
770 zmap
= allocbitmap(N_ZMAP
);
771 spec_imap
= allocbitmap(N_IMAP
);
772 spec_zmap
= allocbitmap(N_ZMAP
);
773 dirmap
= allocbitmap(N_IMAP
);
776 /* Release all the space taken by the bitmaps. */
781 freebitmap(spec_imap
);
782 freebitmap(spec_zmap
);
786 /* `w1' and `w2' are differing words from two bitmaps that should be
787 * identical. Print what's the matter with them.
789 void chkword(w1
, w2
, bit
, type
, n
, report
, phys
)
796 for (; (w1
| w2
); w1
>>= 1, w2
>>= 1, bit
++, phys
++)
797 if ((w1
^ w2
) & 1 && ++(*n
) % MAXPRINT
== 0 && *report
&&
798 (!repair
|| automatic
|| yes("stop this listing")))
802 if ((w1
& 1) && !(w2
& 1))
803 printf("%s %d is missing\n", type
, bit
);
804 else if (!(w1
& 1) && (w2
& 1))
805 printf("%s %d is not free\n", type
, bit
);
810 /* Check if the given (correct) bitmap is identical with the one that is
811 * on the disk. If not, ask if the disk should be repaired.
813 void chkmap(cmap
, dmap
, bit
, blkno
, nblk
, type
)
814 bitchunk_t
*cmap
, *dmap
;
820 register bitchunk_t
*p
= dmap
, *q
= cmap
;
821 int report
= 1, nerr
= 0;
822 int w
= nblk
* WORDS_PER_BLOCK
;
825 printf("Checking %s map. ", type
);
826 if(!preen
) printf("\n");
828 loadbitmap(dmap
, blkno
, nblk
);
830 if (*p
!= *q
) chkword(*p
, *q
, bit
, type
, &nerr
, &report
, phys
);
833 bit
+= 8 * sizeof(bitchunk_t
);
834 phys
+= 8 * sizeof(bitchunk_t
);
837 if ((!repair
|| automatic
) && !report
) printf("etc. ");
838 if (nerr
> MAXPRINT
|| nerr
> 10) printf("%d errors found. ", nerr
);
839 if (nerr
!= 0 && yes("install a new map")) dumpbitmap(cmap
, blkno
, nblk
);
840 if (nerr
> 0) printf("\n");
843 /* See if the inodes that aren't allocated are cleared. */
846 register ino_t ino
= 1;
849 printf("Checking inode list. ");
850 if(!preen
) printf("\n");
853 if (!bitset(imap
, (bit_nr
) ino
)) {
854 devread(inoblock(ino
), inooff(ino
), (char *) &mode
,
856 if (mode
!= I_NOT_ALLOC
) {
857 printf("mode inode %llu not cleared", ino
);
858 if (yes(". clear")) devwrite(inoblock(ino
),
859 inooff(ino
), nullbuf
, INODE_SIZE
);
862 while (++ino
<= sb
.s_ninodes
&& ino
!= 0);
863 if(!preen
) printf("\n");
866 /* Allocate an array to maintain the inode reference counts in. */
869 count
= (nlink_t
*) alloc((unsigned) (sb
.s_ninodes
+ 1), sizeof(nlink_t
));
872 /* The reference count for inode `ino' is wrong. Ask if it should be adjusted. */
873 void counterror(ino_t ino
)
878 printf("INODE NLINK COUNT\n");
881 devread(inoblock(ino
), inooff(ino
), (char *) &inode
, INODE_SIZE
);
882 count
[ino
] += inode
.i_nlinks
; /* it was already subtracted; add it back */
883 printf("%5llu %5u %5u", ino
, (unsigned) inode
.i_nlinks
, count
[ino
]);
884 if (yes(" adjust")) {
885 if ((inode
.i_nlinks
= count
[ino
]) == 0) {
886 fatal("internal error (counterror)");
887 inode
.i_mode
= I_NOT_ALLOC
;
888 clrbit(imap
, (bit_nr
) ino
);
890 devwrite(inoblock(ino
), inooff(ino
), (char *) &inode
, INODE_SIZE
);
894 /* Check if the reference count of the inodes are correct. The array `count'
895 * is maintained as follows: an entry indexed by the inode number is
896 * incremented each time a link is found; when the inode is read the link
897 * count in there is substracted from the corresponding entry in `count'.
898 * Thus, when the whole file system has been traversed, all the entries
905 for (ino
= 1; ino
<= sb
.s_ninodes
&& ino
!= 0; ino
++)
906 if (count
[ino
] != 0) counterror(ino
);
907 if (!firstcnterr
) printf("\n");
910 /* Deallocate the `count' array. */
913 free((char *) count
);
916 /* Print the inode permission bits given by mode and shift. */
917 void printperm(mode_t mode
, int shift
, int special
, int overlay
)
919 if (mode
>> shift
& R_BIT
)
923 if (mode
>> shift
& W_BIT
)
930 if (mode
>> shift
& X_BIT
)
936 /* List the given inode. */
937 void list(ino_t ino
, d_inode
*ip
)
941 printf(" inode permission link size name\n");
943 printf("%6llu ", ino
);
944 switch (ip
->i_mode
& I_TYPE
) {
945 case I_REGULAR
: putchar('-'); break;
946 case I_DIRECTORY
: putchar('d'); break;
947 case I_CHAR_SPECIAL
: putchar('c'); break;
948 case I_BLOCK_SPECIAL
: putchar('b'); break;
949 case I_NAMED_PIPE
: putchar('p'); break;
950 case I_UNIX_SOCKET
: putchar('s'); break;
951 #ifdef I_SYMBOLIC_LINK
952 case I_SYMBOLIC_LINK
: putchar('l'); break;
954 default: putchar('?');
956 printperm(ip
->i_mode
, 6, I_SET_UID_BIT
, 's');
957 printperm(ip
->i_mode
, 3, I_SET_GID_BIT
, 's');
958 printperm(ip
->i_mode
, 0, STICKY_BIT
, 't');
959 printf(" %3u ", ip
->i_nlinks
);
960 switch (ip
->i_mode
& I_TYPE
) {
962 case I_BLOCK_SPECIAL
:
963 printf(" %2x,%2x ", major(ip
->i_zone
[0]), minor(ip
->i_zone
[0]));
965 default: printf("%7d ", ip
->i_size
);
970 /* Remove an entry from a directory if ok with the user.
971 * Don't name the function remove() - that is owned by ANSI, and chaos results
972 * when it is a macro.
974 int Remove(dir_struct
*dp
)
976 setbit(spec_imap
, (bit_nr
) dp
->d_inum
);
977 if (yes(". remove entry")) {
979 memset((void *) dp
, 0, sizeof(dir_struct
));
985 /* Convert string so that embedded control characters are printable. */
986 void make_printable_name(dst
, src
, n
)
993 while (--n
>= 0 && (c
= *src
++) != '\0') {
994 if (isprint(c
) && c
!= '\\')
1000 *dst
++ = '\\'; break;
1002 *dst
++ = 'b'; break;
1004 *dst
++ = 'f'; break;
1006 *dst
++ = 'n'; break;
1008 *dst
++ = 'r'; break;
1010 *dst
++ = 't'; break;
1012 *dst
++ = '0' + ((c
>> 6) & 03);
1013 *dst
++ = '0' + ((c
>> 3) & 07);
1014 *dst
++ = '0' + (c
& 07);
1021 /* See if the `.' or `..' entry is as expected. */
1022 int chkdots(ino_t ino
, off_t pos
, dir_struct
*dp
, ino_t exp
)
1024 char printable_name
[4 * MFS_NAME_MAX
+ 1];
1026 if (dp
->d_inum
!= exp
) {
1027 make_printable_name(printable_name
, dp
->mfs_d_name
,
1028 sizeof(dp
->mfs_d_name
));
1029 printf("bad %s in ", printable_name
);
1031 printf("%s is linked to %u ", printable_name
, dp
->d_inum
);
1032 printf("instead of %llu)", exp
);
1033 setbit(spec_imap
, (bit_nr
) ino
);
1034 setbit(spec_imap
, (bit_nr
) dp
->d_inum
);
1035 setbit(spec_imap
, (bit_nr
) exp
);
1036 if (yes(". repair")) {
1037 count
[dp
->d_inum
]--;
1042 } else if (pos
!= (dp
->mfs_d_name
[1] ? DIR_ENTRY_SIZE
: 0)) {
1043 make_printable_name(printable_name
, dp
->mfs_d_name
,
1044 sizeof(dp
->mfs_d_name
));
1045 printf("warning: %s has offset %lld in ", printable_name
, pos
);
1047 printf("%s is linked to %u)\n", printable_name
, dp
->d_inum
);
1048 setbit(spec_imap
, (bit_nr
) ino
);
1049 setbit(spec_imap
, (bit_nr
) dp
->d_inum
);
1050 setbit(spec_imap
, (bit_nr
) exp
);
1055 /* Check the name in a directory entry. */
1056 int chkname(ino_t ino
, dir_struct
*dp
)
1058 register int n
= MFS_NAME_MAX
+ 1;
1059 register char *p
= dp
->mfs_d_name
;
1062 printf("null name found in ");
1064 setbit(spec_imap
, (bit_nr
) ino
);
1065 if (Remove(dp
)) return(0);
1067 while (*p
!= '\0' && --n
!= 0)
1069 printf("found a '/' in entry of directory ");
1071 setbit(spec_imap
, (bit_nr
) ino
);
1072 printf("entry = '");
1073 printname(dp
->mfs_d_name
);
1075 if (Remove(dp
)) return(0);
1081 /* Check a directory entry. Here the routine `descendtree' is called
1082 * recursively to check the file or directory pointed to by the entry.
1084 int chkentry(ino_t ino
, off_t pos
, dir_struct
*dp
)
1086 if (dp
->d_inum
< ROOT_INODE
|| dp
->d_inum
> sb
.s_ninodes
) {
1087 printf("bad inode found in directory ");
1089 printf("ino found = %u, ", dp
->d_inum
);
1091 printname(dp
->mfs_d_name
);
1093 if (yes(". remove entry")) {
1094 memset((void *) dp
, 0, sizeof(dir_struct
));
1099 if ((unsigned) count
[dp
->d_inum
] == SHRT_MAX
) {
1100 printf("too many links to ino %u\n", dp
->d_inum
);
1101 printf("discovered at entry '");
1102 printname(dp
->mfs_d_name
);
1103 printf("' in directory ");
1105 if (Remove(dp
)) return(0);
1107 count
[dp
->d_inum
]++;
1108 if (strcmp(dp
->mfs_d_name
, ".") == 0) {
1109 ftop
->st_presence
|= DOT
;
1110 return(chkdots(ino
, pos
, dp
, ino
));
1112 if (strcmp(dp
->mfs_d_name
, "..") == 0) {
1113 ftop
->st_presence
|= DOTDOT
;
1114 return(chkdots(ino
, pos
, dp
, ino
== ROOT_INODE
? ino
:
1115 ftop
->st_next
->st_dir
->d_inum
));
1117 if (!chkname(ino
, dp
)) return(0);
1118 if (bitset(dirmap
, (bit_nr
) dp
->d_inum
)) {
1119 printf("link to directory discovered in ");
1122 printname(dp
->mfs_d_name
);
1123 printf("', dir ino = %u)", dp
->d_inum
);
1126 return(descendtree(dp
));
1129 /* Check a zone of a directory by checking all the entries in the zone.
1130 * The zone is split up into chunks to not allocate too much stack.
1132 int chkdirzone(ino_t ino
, d_inode
*ip
, off_t pos
, zone_nr zno
)
1134 dir_struct dirblk
[CDIRECT
];
1135 register dir_struct
*dp
;
1136 register int n
, dirty
;
1137 long block
= ztob(zno
);
1138 register long offset
= 0;
1139 register off_t size
= 0;
1140 n
= SCALE
* (NR_DIR_ENTRIES(block_size
) / CDIRECT
);
1143 devread(block
, offset
, (char *) dirblk
, DIRCHUNK
);
1145 for (dp
= dirblk
; dp
< &dirblk
[CDIRECT
]; dp
++) {
1146 if (dp
->d_inum
!= NO_ENTRY
&& !chkentry(ino
, pos
, dp
))
1148 pos
+= DIR_ENTRY_SIZE
;
1149 if (dp
->d_inum
!= NO_ENTRY
) size
= pos
;
1151 if (dirty
) devwrite(block
, offset
, (char *) dirblk
, DIRCHUNK
);
1156 if (size
> ip
->i_size
) {
1157 printf("size not updated of directory ");
1159 if (yes(". extend")) {
1160 setbit(spec_imap
, (bit_nr
) ino
);
1162 devwrite(inoblock(ino
), inooff(ino
), (char *) ip
, INODE_SIZE
);
1169 int chksymlinkzone(ino_t ino
, d_inode
*ip
, off_t pos
, zone_nr zno
)
1173 char target
[PATH_MAX
+1];
1175 if (ip
->i_size
> PATH_MAX
)
1176 fatal("chksymlinkzone: fsck program inconsistency\n");
1178 devread(block
, 0, target
, ip
->i_size
);
1179 target
[ip
->i_size
]= '\0';
1180 len
= strlen(target
);
1181 if (len
!= ip
->i_size
)
1183 printf("bad size in symbolic link (%d instead of %d) ",
1186 if (yes(". update")) {
1187 setbit(spec_imap
, (bit_nr
) ino
);
1189 devwrite(inoblock(ino
), inooff(ino
),
1190 (char *) ip
, INODE_SIZE
);
1196 /* There is something wrong with the given zone. Print some details. */
1197 void errzone(mess
, zno
, level
, pos
)
1203 printf("%s zone in ", mess
);
1205 printf("zno = %d, type = ", zno
);
1207 case 0: printf("DATA"); break;
1208 case 1: printf("SINGLE INDIRECT"); break;
1209 case 2: printf("DOUBLE INDIRECT"); break;
1210 default: printf("VERY INDIRECT");
1212 printf(", pos = %lld)\n", pos
);
1215 /* Found the given zone in the given inode. Check it, and if ok, mark it
1216 * in the zone bitmap.
1218 int markzone(zno
, level
, pos
)
1223 register bit_nr bit
= (bit_nr
) zno
- FIRST
+ 1;
1226 if (zno
< FIRST
|| zno
>= sb
.s_zones
) {
1227 errzone("out-of-range", zno
, level
, pos
);
1230 if (bitset(zmap
, bit
)) {
1231 setbit(spec_zmap
, bit
);
1232 errzone("duplicate", zno
, level
, pos
);
1236 if (bitset(spec_zmap
, bit
)) errzone("found", zno
, level
, pos
);
1241 /* Check an indirect zone by checking all of its entries.
1242 * The zone is split up into chunks to not allocate too much stack.
1244 int chkindzone(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr zno
, int level
)
1246 zone_nr indirect
[CINDIR
];
1247 register int n
= NR_INDIRECTS
/ CINDIR
;
1248 long block
= ztob(zno
);
1249 register long offset
= 0;
1252 devread(block
, offset
, (char *) indirect
, INDCHUNK
);
1253 if (!chkzones(ino
, ip
, pos
, indirect
, CINDIR
, level
- 1)) return(0);
1255 } while (--n
&& *pos
< ip
->i_size
);
1259 /* Return the size of a gap in the file, represented by a null zone number
1260 * at some level of indirection.
1265 off_t power
= ZONE_SIZE
;
1268 power
*= NR_INDIRECTS
;
1273 /* Check a zone, which may be either a normal data zone, a directory zone,
1274 * or an indirect zone.
1276 int zonechk(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr zno
, int level
)
1279 if ((ip
->i_mode
& I_TYPE
) == I_DIRECTORY
&&
1280 !chkdirzone(ino
, ip
, *pos
, zno
))
1282 if ((ip
->i_mode
& I_TYPE
) == I_SYMBOLIC_LINK
&&
1283 !chksymlinkzone(ino
, ip
, *pos
, zno
))
1288 return chkindzone(ino
, ip
, pos
, zno
, level
);
1291 /* Check a list of zones given by `zlist'. */
1292 int chkzones(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr
*zlist
,
1295 register int ok
= 1, i
;
1297 /* The check on the position in the next loop is commented out, since FS
1298 * now requires valid zone numbers in each level that is necessary and FS
1299 * always deleted all the zones in the double indirect block.
1301 for (i
= 0; i
< len
/* && *pos < ip->i_size */ ; i
++)
1302 if (zlist
[i
] == NO_ZONE
)
1303 *pos
+= jump(level
);
1304 else if (!markzone(zlist
[i
], level
, *pos
)) {
1305 *pos
+= jump(level
);
1307 } else if (!zonechk(ino
, ip
, pos
, zlist
[i
], level
))
1312 /* Check a file or a directory. */
1313 int chkfile(ino_t ino
, d_inode
*ip
)
1315 register int ok
, i
, level
;
1318 ok
= chkzones(ino
, ip
, &pos
, &ip
->i_zone
[0], NR_DZONE_NUM
, 0);
1319 for (i
= NR_DZONE_NUM
, level
= 1; i
< NR_ZONE_NUMS
; i
++, level
++)
1320 ok
&= chkzones(ino
, ip
, &pos
, &ip
->i_zone
[i
], 1, level
);
1324 /* Check a directory by checking the contents. Check if . and .. are present. */
1325 int chkdirectory(ino_t ino
, d_inode
*ip
)
1329 setbit(dirmap
, (bit_nr
) ino
);
1330 ok
= chkfile(ino
, ip
);
1331 if (!(ftop
->st_presence
& DOT
)) {
1332 printf(". missing in ");
1336 if (!(ftop
->st_presence
& DOTDOT
)) {
1337 printf(".. missing in ");
1344 #ifdef I_SYMBOLIC_LINK
1346 /* Check the validity of a symbolic link. */
1347 int chklink(ino_t ino
, d_inode
*ip
)
1351 ok
= chkfile(ino
, ip
);
1352 if (ip
->i_size
<= 0 || ip
->i_size
> block_size
) {
1353 if (ip
->i_size
== 0)
1354 printf("empty symbolic link ");
1356 printf("symbolic link too large (size %d) ", ip
->i_size
);
1365 /* Check the validity of a special file. */
1366 int chkspecial(ino_t ino
, d_inode
*ip
)
1371 if ((dev_t
) ip
->i_zone
[0] == NO_DEV
) {
1372 printf("illegal device number %d for special file ", ip
->i_zone
[0]);
1377 /* FS will not use the remaining "zone numbers" but 1.6.11++ will panic if
1378 * they are nonzero, since this should not happen.
1380 for (i
= 1; i
< NR_ZONE_NUMS
; i
++)
1381 if (ip
->i_zone
[i
] != NO_ZONE
) {
1382 printf("nonzero zone number %d for special file ",
1390 /* Check the mode and contents of an inode. */
1391 int chkmode(ino_t ino
, d_inode
*ip
)
1393 switch (ip
->i_mode
& I_TYPE
) {
1396 return chkfile(ino
, ip
);
1399 return chkdirectory(ino
, ip
);
1400 case I_BLOCK_SPECIAL
:
1402 return chkspecial(ino
, ip
);
1403 case I_CHAR_SPECIAL
:
1405 return chkspecial(ino
, ip
);
1408 return chkfile(ino
, ip
);
1411 return chkfile(ino
, ip
);
1412 #ifdef I_SYMBOLIC_LINK
1413 case I_SYMBOLIC_LINK
:
1415 return chklink(ino
, ip
);
1419 printf("bad mode of ");
1421 printf("mode = %o)", ip
->i_mode
);
1426 /* Check an inode. */
1427 int chkinode(ino_t ino
, d_inode
*ip
)
1429 if (ino
== ROOT_INODE
&& (ip
->i_mode
& I_TYPE
) != I_DIRECTORY
) {
1430 printf("root inode is not a directory ");
1431 printf("(ino = %llu, mode = %o)\n", ino
, ip
->i_mode
);
1434 if (ip
->i_nlinks
== 0) {
1435 printf("link count zero of ");
1440 setbit(imap
, (bit_nr
) ino
);
1441 if ((unsigned) ip
->i_nlinks
> SHRT_MAX
) {
1442 printf("link count too big in ");
1444 printf("cnt = %u)\n", (unsigned) ip
->i_nlinks
);
1445 count
[ino
] -= SHRT_MAX
;
1446 setbit(spec_imap
, (bit_nr
) ino
);
1448 count
[ino
] -= (unsigned) ip
->i_nlinks
;
1450 return chkmode(ino
, ip
);
1453 /* Check the directory entry pointed to by dp, by checking the inode. */
1458 register ino_t ino
= dp
->d_inum
;
1459 register int visited
;
1465 if (bitset(spec_imap
, (bit_nr
) ino
)) {
1466 printf("found inode %llu: ", ino
);
1469 visited
= bitset(imap
, (bit_nr
) ino
);
1470 if (!visited
|| listing
) {
1471 devread(inoblock(ino
), inooff(ino
), (char *) &inode
, INODE_SIZE
);
1472 if (listing
) list(ino
, &inode
);
1473 if (!visited
&& !chkinode(ino
, &inode
)) {
1474 setbit(spec_imap
, (bit_nr
) ino
);
1475 if (yes("remove")) {
1476 count
[ino
] += inode
.i_nlinks
- 1;
1477 clrbit(imap
, (bit_nr
) ino
);
1478 devwrite(inoblock(ino
), inooff(ino
),
1479 nullbuf
, INODE_SIZE
);
1480 memset((void *) dp
, 0, sizeof(dir_struct
));
1481 ftop
= ftop
->st_next
;
1486 ftop
= ftop
->st_next
;
1490 /* Check the file system tree. */
1495 nfreeinode
= sb
.s_ninodes
;
1497 dir
.d_inum
= ROOT_INODE
;
1498 dir
.mfs_d_name
[0] = 0;
1499 if (!descendtree(&dir
)) fatal("bad root inode");
1503 /* Print the totals of all the objects found. */
1507 printf("%d files, %d directories, %d free inodes, %ld free zones\n",
1508 nregular
, ndirectory
, nfreeinode
, nfreezone
);
1512 printf("blocksize = %5d ", block_size
);
1513 printf("zonesize = %5d\n", ZONE_SIZE
);
1515 pr("%8u Regular file%s\n", nregular
, "", "s");
1516 pr("%8u Director%s\n", ndirectory
, "y", "ies");
1517 pr("%8u Block special file%s\n", nblkspec
, "", "s");
1518 pr("%8u Character special file%s\n", ncharspec
, "", "s");
1519 if (nbadinode
!= 0) pr("%6u Bad inode%s\n", nbadinode
, "", "s");
1520 pr("%8u Free inode%s\n", nfreeinode
, "", "s");
1521 pr("%8u Named pipe%s\n", npipe
, "", "s");
1522 pr("%8u Unix socket%s\n", nsock
, "", "s");
1523 pr("%8u Symbolic link%s\n", nsyml
, "", "s");
1524 /* Don't print some fields.
1526 pr("%8u Data zone%s\n", ztype[0], "", "s");
1527 pr("%8u Single indirect zone%s\n", ztype[1], "", "s");
1528 pr("%8u Double indirect zone%s\n", ztype[2], "", "s");
1530 lpr("%8ld Free zone%s\n", nfreezone
, "", "s");
1533 /* Check the device which name is given by `f'. The inodes listed by `clist'
1534 * should be listed separately, and the inodes listed by `ilist' and the zones
1535 * listed by `zlist' should be watched for while checking the file system.
1538 void chkdev(f
, clist
, ilist
, zlist
)
1539 char *f
, **clist
, **ilist
, **zlist
;
1541 if (automatic
) repair
= 1;
1547 rw_super(SUPER_GET
);
1549 if(block_size
< SUPER_BLOCK_BYTES
)
1550 fatal("funny block size");
1552 if(!(rwbuf
= malloc(block_size
))) fatal("couldn't allocate fs buf (1)");
1553 if(!(nullbuf
= malloc(block_size
))) fatal("couldn't allocate fs buf (2)");
1554 memset(nullbuf
, 0, block_size
);
1559 if(sb
.s_flags
& MFSFLAG_CLEAN
) {
1560 sb
.s_flags
&= ~MFSFLAG_CLEAN
;
1561 rw_super(SUPER_PUT
);
1562 printf("\n----- FILE SYSTEM MARKED DIRTY -----\n\n");
1564 printf("Filesystem is already dirty.\n");
1568 /* If preening, skip fsck if clean flag is on. */
1570 if(sb
.s_flags
& MFSFLAG_CLEAN
) {
1571 printf("%s: clean\n", f
);
1574 printf("%s: dirty, performing fsck\n", f
);
1581 fillbitmap(spec_imap
, (bit_nr
) 1, (bit_nr
) sb
.s_ninodes
+ 1, ilist
);
1582 fillbitmap(spec_zmap
, (bit_nr
) FIRST
, (bit_nr
) sb
.s_zones
, zlist
);
1586 chkmap(zmap
, spec_zmap
, (bit_nr
) FIRST
- 1, BLK_ZMAP
, N_ZMAP
, "zone");
1588 chkmap(imap
, spec_imap
, (bit_nr
) 0, BLK_IMAP
, N_IMAP
, "inode");
1590 if(preen
) printf("\n");
1596 if (changed
) printf("\n----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
1598 /* If we were told to repair the FS, and the user never stopped us from
1599 * doing it, and the FS wasn't marked clean, we can mark the FS as clean.
1600 * If we were stopped from repairing, tell user about it.
1602 if(repair
&& !(sb
.s_flags
& MFSFLAG_CLEAN
)) {
1604 printf("\n----- FILE SYSTEM STILL DIRTY -----\n\n");
1606 sync(); /* update FS on disk before clean flag */
1607 sb
.s_flags
|= MFSFLAG_CLEAN
;
1608 rw_super(SUPER_PUT
);
1609 printf("\n----- FILE SYSTEM MARKED CLEAN -----\n\n");
1616 int main(argc
, argv
)
1620 register char **clist
= 0, **ilist
= 0, **zlist
= 0;
1623 register int devgiven
= 0;
1626 if ((1 << BITSHIFT
) != 8 * sizeof(bitchunk_t
)) {
1627 printf("Fsck was compiled with the wrong BITSHIFT!\n");
1628 exit(FSCK_EXIT_CHECK_FAILED
);
1633 while ((arg
= *argv
++) != 0)
1634 if (arg
[0] == '-' && arg
[1] != 0 && arg
[2] == 0) switch (arg
[1]) {
1635 case 'd': markdirty
= 1; break;
1636 case 'p': preen
= repair
= automatic
= 1; break;
1638 case 'a': automatic
^= 1; break;
1640 clist
= getlist(&argv
, "inode");
1643 ilist
= getlist(&argv
, "inode");
1646 zlist
= getlist(&argv
, "zone");
1648 case 'r': repair
^= 1; break;
1649 case 'l': listing
^= 1; break;
1650 case 's': listsuper
^= 1; break;
1653 printf("%s: unknown flag '%s'\n", prog
, arg
);
1657 chkdev(arg
, clist
, ilist
, zlist
);
1663 if (!devgiven
|| badflag
) {
1664 printf("Usage: fsck [-dyfpacilrsz] file\n");
1665 exit(FSCK_EXIT_USAGE
);
1670 void panic(char *fmt
, ...)
1672 fprintf(stderr
, "%s\n", fmt
);