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/u64.h>
50 #include "mfs/const.h"
51 #include "mfs/inode.h"
53 #include "mfs/mfsdir.h"
54 #include <minix/fslib.h>
61 #include "exitvalues.h"
65 unsigned int fs_version
= 2, block_size
= 0;
67 #define BITSHIFT 5 /* = log2(#bits(int)) */
69 #define MAXPRINT 80 /* max. number of error lines in chkmap */
70 #define CINDIR 128 /* number of indirect zno's read at a time */
71 #define CDIRECT 1 /* number of dir entries read at a time */
73 /* Macros for handling bitmaps. Now bit_t is long, these are bulky and the
74 * type demotions produce a lot of lint. The explicit demotion in POWEROFBIT
75 * is for efficiency and assumes 2's complement ints. Lint should be clever
76 * enough not to warn about it since BITMASK is small, but isn't. (It would
77 * be easier to get right if bit_t was was unsigned (long) since then there
78 * would be no danger from wierd sign representations. Lint doesn't know
79 * we only use non-negative bit numbers.) There will usually be an implicit
80 * demotion when WORDOFBIT is used as an array index. This should be safe
81 * since memory for bitmaps will run out first.
83 #define BITMASK ((1 << BITSHIFT) - 1)
84 #define WORDOFBIT(b) ((b) >> BITSHIFT)
85 #define POWEROFBIT(b) (1 << ((int) (b) & BITMASK))
86 #define setbit(w, b) (w[WORDOFBIT(b)] |= POWEROFBIT(b))
87 #define clrbit(w, b) (w[WORDOFBIT(b)] &= ~POWEROFBIT(b))
88 #define bitset(w, b) (w[WORDOFBIT(b)] & POWEROFBIT(b))
90 #define ZONE_CT 360 /* default zones (when making file system) */
91 #define INODE_CT 95 /* default inodes (when making file system) */
93 #include "mfs/super.h"
94 static struct super_block sb
;
96 #define STICKY_BIT 01000 /* not defined anywhere else */
98 /* Ztob gives the block address of a zone
99 * btoa64 gives the byte address of a block
101 #define ztob(z) ((block_nr) (z) << sb.s_log_zone_size)
102 #define btoa64(b) (mul64u(b, block_size))
103 #define SCALE ((int) ztob(1)) /* # blocks in a zone */
104 #define FIRST ((zone_nr) sb.s_firstdatazone) /* as the name says */
106 /* # blocks of each type */
107 #define N_IMAP (sb.s_imap_blocks)
108 #define N_ZMAP (sb.s_zmap_blocks)
109 #define N_ILIST ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
110 #define N_DATA (sb.s_zones - FIRST)
112 /* Block address of each type */
113 #define OFFSET_SUPER_BLOCK SUPER_BLOCK_BYTES
115 #define BLK_ZMAP (BLK_IMAP + N_IMAP)
116 #define BLK_ILIST (BLK_ZMAP + N_ZMAP)
117 #define BLK_FIRST ztob(FIRST)
118 #define ZONE_SIZE ((int) ztob(block_size))
119 #define NLEVEL (NR_ZONE_NUMS - NR_DZONE_NUM + 1)
121 /* Byte address of a zone */
122 #define INDCHUNK ((int) (CINDIR * ZONE_NUM_SIZE))
123 #define DIRCHUNK ((int) (CDIRECT * DIR_ENTRY_SIZE))
125 char *prog
, *fsck_device
; /* program name (fsck), device name */
126 int firstcnterr
; /* is this the first inode ref cnt error? */
127 bitchunk_t
*imap
, *spec_imap
; /* inode bit maps */
128 bitchunk_t
*zmap
, *spec_zmap
; /* zone bit maps */
129 bitchunk_t
*dirmap
; /* directory (inode) bit map */
130 char *rwbuf
; /* one block buffer cache */
131 block_nr thisblk
; /* block in buffer cache */
132 char *nullbuf
; /* null buffer */
133 nlink_t
*count
; /* inode count */
134 int changed
; /* has the diskette been written to? */
137 struct stack
*st_next
;
141 int dev
; /* file descriptor of the device */
146 /* Counters for each type of inode/zone. */
147 int nfreeinode
, nregular
, ndirectory
, nblkspec
, ncharspec
, nbadinode
;
148 int nsock
, npipe
, nsyml
, ztype
[NLEVEL
];
151 int repair
, notrepaired
= 0, automatic
, listing
, listsuper
; /* flags */
152 int preen
= 0, markdirty
= 0;
153 int firstlist
; /* has the listing header been printed? */
154 unsigned part_offset
; /* sector offset for this partition */
155 char answer
[] = "Answer questions with y or n. Then hit RETURN";
157 int main(int argc
, char **argv
);
161 int yes(char *question
);
163 int input(char *buf
, int size
);
164 char *alloc(unsigned nelem
, unsigned elsize
);
165 void printname(char *s
);
166 void printrec(struct stack
*sp
);
167 void printpath(int mode
, int nlcr
);
170 void devio(block_nr bno
, int dir
);
171 void devread(long block
, long offset
, char *buf
, int size
);
172 void devwrite(long block
, long offset
, char *buf
, int size
);
173 void pr(char *fmt
, int cnt
, char *s
, char *p
);
174 void lpr(char *fmt
, long cnt
, char *s
, char *p
);
175 bit_nr
getnumber(char *s
);
176 char **getlist(char ***argv
, char *type
);
180 void rw_super(int mode
);
182 void lsi(char **clist
);
183 bitchunk_t
*allocbitmap(int nblk
);
184 void loadbitmap(bitchunk_t
*bitmap
, block_nr bno
, int nblk
);
185 void dumpbitmap(bitchunk_t
*bitmap
, block_nr bno
, int nblk
);
186 void fillbitmap(bitchunk_t
*bitmap
, bit_nr lwb
, bit_nr upb
, char
188 void freebitmap(bitchunk_t
*p
);
189 void getbitmaps(void);
190 void putbitmaps(void);
191 void chkword(unsigned w1
, unsigned w2
, bit_nr bit
, char *type
, int *n
,
193 void chkmap(bitchunk_t
*cmap
, bitchunk_t
*dmap
, bit_nr bit
, block_nr
194 blkno
, int nblk
, char *type
);
197 void counterror(ino_t ino
);
199 void freecount(void);
200 void printperm(mode_t mode
, int shift
, int special
, int overlay
);
201 void list(ino_t ino
, d_inode
*ip
);
202 int Remove(dir_struct
*dp
);
203 void make_printable_name(char *dst
, char *src
, int n
);
204 int chkdots(ino_t ino
, off_t pos
, dir_struct
*dp
, ino_t exp
);
205 int chkname(ino_t ino
, dir_struct
*dp
);
206 int chkentry(ino_t ino
, off_t pos
, dir_struct
*dp
);
207 int chkdirzone(ino_t ino
, d_inode
*ip
, off_t pos
, zone_nr zno
);
208 int chksymlinkzone(ino_t ino
, d_inode
*ip
, off_t pos
, zone_nr zno
);
209 void errzone(char *mess
, zone_nr zno
, int level
, off_t pos
);
210 int markzone(zone_nr zno
, int level
, off_t pos
);
211 int chkindzone(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr zno
, int
213 off_t
jump(int level
);
214 int zonechk(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr zno
, int level
);
215 int chkzones(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr
*zlist
, int
217 int chkfile(ino_t ino
, d_inode
*ip
);
218 int chkdirectory(ino_t ino
, d_inode
*ip
);
219 int chklink(ino_t ino
, d_inode
*ip
);
220 int chkspecial(ino_t ino
, d_inode
*ip
);
221 int chkmode(ino_t ino
, d_inode
*ip
);
222 int chkinode(ino_t ino
, d_inode
*ip
);
223 int descendtree(dir_struct
*dp
);
225 void printtotal(void);
226 void chkdev(char *f
, char **clist
, char **ilist
, char **zlist
);
228 /* Initialize the variables used by this program. */
233 nregular
= ndirectory
= nblkspec
= ncharspec
=
234 nbadinode
= nsock
= npipe
= nsyml
= 0;
235 for (level
= 0; level
< NLEVEL
; level
++) ztype
[level
] = 0;
242 /* Print the string `s' and exit. */
246 printf("%s\nfatal\n", s
);
247 exit(FSCK_EXIT_CHECK_FAILED
);
250 /* Test for end of line. */
254 return(c
== EOF
|| c
== '\n' || c
== '\r');
257 /* Ask a question and get the answer unless automatic is set. */
261 register int c
, answerchar
;
269 printf("%s? ", question
);
270 if(!note
) { printf("(y=yes, n=no, q=quit, A=for yes to all) "); note
= 1; }
276 if ((c
= answerchar
= getchar()) == 'q' || c
== 'Q') exit(FSCK_EXIT_CHECK_FAILED
);
277 if(c
== 'A') { automatic
= 1; c
= 'y'; }
278 while (!eoln(c
)) c
= getchar();
279 yes
= !(answerchar
== 'n' || answerchar
== 'N');
280 if(!yes
) notrepaired
= 1;
284 /* Convert string to integer. Representation is octal. */
290 while ('0' <= *s
&& *s
< '8') {
297 /* If repairing the file system, print a prompt and get a string from user. */
302 register char *p
= buf
;
317 while (!eoln(getchar()));
323 /* Allocate some memory and zero it. */
324 char *alloc(nelem
, elsize
)
325 unsigned nelem
, elsize
;
329 if ((p
= (char *)malloc((size_t)nelem
* elsize
)) == 0) {
330 fprintf(stderr
, "Tried to allocate %dkB\n",
332 fatal("out of memory");
334 memset((void *) p
, 0, (size_t)nelem
* elsize
);
338 /* Print the name in a directory entry. */
342 register n
= MFS_NAME_MAX
;
346 if ((c
= *s
) == 0) break;
347 if (!isprint(c
)) c
= '?';
353 /* Print the pathname given by a linked list pointed to by `sp'. The
354 * names are in reverse order.
356 void printrec(struct stack
*sp
)
358 if (sp
->st_next
!= 0) {
359 printrec(sp
->st_next
);
361 printname(sp
->st_dir
->mfs_d_name
);
365 /* Print the current pathname. */
366 void printpath(mode
, nlcr
)
370 if (ftop
->st_next
== 0)
376 printf(" (ino = %u, ", ftop
->st_dir
->d_inum
);
379 printf(" (ino = %u)", ftop
->st_dir
->d_inum
);
382 if (nlcr
) printf("\n");
385 /* Open the device. */
388 if ((dev
= open(fsck_device
,
389 (repair
|| markdirty
) ? O_RDWR
: O_RDONLY
)) < 0) {
391 fatal("couldn't open device to fsck");
395 /* Close the device. */
398 if (close(dev
) != 0) {
404 /* Read or write a block. */
411 if(!block_size
) fatal("devio() with unknown block size");
412 if (dir
== READING
&& bno
== thisblk
) return;
416 printf("%s at block %5d\n", dir
== READING
? "reading " : "writing", bno
);
418 r
= lseek64(dev
, btoa64(bno
), SEEK_SET
, NULL
);
420 fatal("lseek64 failed");
421 if (dir
== READING
) {
422 if (read(dev
, rwbuf
, block_size
) == block_size
)
425 if (write(dev
, rwbuf
, block_size
) == block_size
)
429 printf("%s: can't %s block %ld (error = 0x%x)\n", prog
,
430 dir
== READING
? "read" : "write", (long) bno
, errno
);
431 if (dir
== READING
) {
432 printf("Continuing with a zero-filled block.\n");
433 memset(rwbuf
, 0, block_size
);
439 /* Read `size' bytes from the disk starting at block 'block' and
442 void devread(block
, offset
, buf
, size
)
448 if(!block_size
) fatal("devread() with unknown block size");
449 if (offset
>= block_size
)
451 block
+= offset
/block_size
;
452 offset
%= block_size
;
454 devio(block
, READING
);
455 memmove(buf
, &rwbuf
[offset
], size
);
458 /* Write `size' bytes to the disk starting at block 'block' and
461 void devwrite(block
, offset
, buf
, size
)
467 if(!block_size
) fatal("devwrite() with unknown block size");
468 if (!repair
) fatal("internal error (devwrite)");
469 if (offset
>= block_size
)
471 block
+= offset
/block_size
;
472 offset
%= block_size
;
474 if (size
!= block_size
) devio(block
, READING
);
475 memmove(&rwbuf
[offset
], buf
, size
);
476 devio(block
, WRITING
);
480 /* Print a string with either a singular or a plural pronoun. */
481 void pr(fmt
, cnt
, s
, p
)
485 printf(fmt
, cnt
, cnt
== 1 ? s
: p
);
488 /* Same as above, but with a long argument */
489 void lpr(fmt
, cnt
, s
, p
)
493 printf(fmt
, cnt
, cnt
== 1 ? s
: p
);
496 /* Convert string to number. */
500 register bit_nr n
= 0;
505 n
= (n
<< 1) + (n
<< 3) + *s
++ - '0';
506 return (*s
== '\0') ? n
: NO_BIT
;
509 /* See if the list pointed to by `argv' contains numbers. */
510 char **getlist(argv
, type
)
513 register char **list
= *argv
;
516 while (getnumber(**argv
) != NO_BIT
) {
521 printf("warning: no %s numbers given\n", type
);
527 /* Make a listing of the super block. If `repair' is set, ask the user
535 /* Most of the following atol's enrage lint, for good reason. */
536 printf("ninodes = %u", sb
.s_ninodes
);
537 if (input(buf
, 80)) sb
.s_ninodes
= atol(buf
);
538 printf("nzones = %ld", sb
.s_zones
);
539 if (input(buf
, 80)) sb
.s_zones
= atol(buf
);
540 printf("imap_blocks = %u", sb
.s_imap_blocks
);
541 if (input(buf
, 80)) sb
.s_imap_blocks
= atol(buf
);
542 printf("zmap_blocks = %u", sb
.s_zmap_blocks
);
543 if (input(buf
, 80)) sb
.s_zmap_blocks
= atol(buf
);
544 printf("firstdatazone = %u", sb
.s_firstdatazone_old
);
545 if (input(buf
, 80)) sb
.s_firstdatazone_old
= atol(buf
);
546 printf("log_zone_size = %u", sb
.s_log_zone_size
);
547 if (input(buf
, 80)) sb
.s_log_zone_size
= atol(buf
);
548 printf("maxsize = %ld", sb
.s_max_size
);
549 if (input(buf
, 80)) sb
.s_max_size
= atol(buf
);
550 printf("block size = %ld", sb
.s_block_size
);
551 if (input(buf
, 80)) sb
.s_block_size
= atol(buf
);
553 devwrite(0, OFFSET_SUPER_BLOCK
, (char *) &sb
, sizeof(sb
));
557 if(sb
.s_flags
& MFSFLAG_CLEAN
) printf("CLEAN "); else printf("DIRTY ");
559 } while (yes("Do you want to try again"));
560 if (repair
) exit(FSCK_EXIT_OK
);
563 /* Get the super block from either disk or user. Do some initial checks. */
564 void rw_super(int put
)
566 if(lseek(dev
, OFFSET_SUPER_BLOCK
, SEEK_SET
) < 0) {
568 fatal("couldn't seek to super block.");
570 if(put
== SUPER_PUT
) {
571 if(write(dev
, &sb
, sizeof(sb
)) != sizeof(sb
)) {
572 fatal("couldn't write super block.");
576 if(read(dev
, &sb
, sizeof(sb
)) != sizeof(sb
)) {
577 fatal("couldn't read super block.");
579 if (listsuper
) lsuper();
580 if (sb
.s_magic
== SUPER_MAGIC
) fatal("Cannot handle V1 file systems");
581 if (sb
.s_magic
== SUPER_V2
) {
583 block_size
= /* STATIC_BLOCK_SIZE */ 8192;
584 } else if(sb
.s_magic
== SUPER_V3
) {
586 block_size
= sb
.s_block_size
;
588 fatal("bad magic number in super block");
590 if (sb
.s_ninodes
<= 0) fatal("no inodes");
591 if (sb
.s_zones
<= 0) fatal("no zones");
592 if (sb
.s_imap_blocks
<= 0) fatal("no imap");
593 if (sb
.s_zmap_blocks
<= 0) fatal("no zmap");
594 if (sb
.s_firstdatazone
!= 0 && sb
.s_firstdatazone
<= 4)
595 fatal("first data zone too small");
596 if (sb
.s_log_zone_size
< 0) fatal("zone size < block size");
597 if (sb
.s_max_size
<= 0) {
598 printf("warning: invalid max file size %ld\n", sb
.s_max_size
);
599 sb
.s_max_size
= LONG_MAX
;
603 /* Check the super block for reasonable contents. */
607 register off_t maxsize
;
609 n
= bitmapsize((bit_t
) sb
.s_ninodes
+ 1, block_size
);
610 if (sb
.s_magic
!= SUPER_V2
&& sb
.s_magic
!= SUPER_V3
)
611 fatal("bad magic number in super block");
612 if (sb
.s_imap_blocks
< n
) {
613 printf("need %d bocks for inode bitmap; only have %d\n",
614 n
, sb
.s_imap_blocks
);
615 fatal("too few imap blocks");
617 if (sb
.s_imap_blocks
!= n
) {
618 pr("warning: expected %d imap_block%s", n
, "", "s");
619 printf(" instead of %d\n", sb
.s_imap_blocks
);
621 n
= bitmapsize((bit_t
) sb
.s_zones
, block_size
);
622 if (sb
.s_zmap_blocks
< n
) fatal("too few zmap blocks");
623 if (sb
.s_zmap_blocks
!= n
) {
624 pr("warning: expected %d zmap_block%s", n
, "", "s");
625 printf(" instead of %d\n", sb
.s_zmap_blocks
);
627 if (sb
.s_log_zone_size
>= 8 * sizeof(block_nr
))
628 fatal("log_zone_size too large");
629 if (sb
.s_log_zone_size
> 8) printf("warning: large log_zone_size (%d)\n",
631 sb
.s_firstdatazone
= (BLK_ILIST
+ N_ILIST
+ SCALE
- 1) >> sb
.s_log_zone_size
;
632 if (sb
.s_firstdatazone_old
!= 0) {
633 if (sb
.s_firstdatazone_old
>= sb
.s_zones
)
634 fatal("first data zone too large");
635 if (sb
.s_firstdatazone_old
< sb
.s_firstdatazone
)
636 fatal("first data zone too small");
637 if (sb
.s_firstdatazone_old
!= sb
.s_firstdatazone
) {
638 printf("warning: expected first data zone to be %u ",
640 printf("instead of %u\n", sb
.s_firstdatazone_old
);
641 sb
.s_firstdatazone
= sb
.s_firstdatazone_old
;
644 maxsize
= MAX_FILE_POS
;
645 if (((maxsize
- 1) >> sb
.s_log_zone_size
) / block_size
>= MAX_ZONES
)
646 maxsize
= ((long) MAX_ZONES
* block_size
) << sb
.s_log_zone_size
;
649 if (sb
.s_max_size
!= maxsize
) {
650 printf("warning: expected max size to be %ld ", maxsize
);
651 printf("instead of %ld\n", sb
.s_max_size
);
654 if(sb
.s_flags
& MFSFLAG_MANDATORY_MASK
) {
655 fatal("unsupported feature bits - newer fsck needed");
659 int inoblock(int inn
)
661 return div64u(mul64u(inn
- 1, INODE_SIZE
), block_size
) + BLK_ILIST
;
666 return rem64u(mul64u(inn
- 1, INODE_SIZE
), block_size
);
669 /* Make a listing of the inodes given by `clist'. If `repair' is set, ask
670 * the user for changes.
677 d_inode inode
, *ip
= &inode
;
680 if (clist
== 0) return;
681 while ((bit
= getnumber(*clist
++)) != NO_BIT
) {
682 setbit(spec_imap
, bit
);
685 devread(inoblock(ino
), inooff(ino
), (char *) ip
, INODE_SIZE
);
686 printf("inode %u:\n", ino
);
687 printf(" mode = %6o", ip
->i_mode
);
688 if (input(buf
, 80)) ip
->i_mode
= atoo(buf
);
689 printf(" nlinks = %6u", ip
->i_nlinks
);
690 if (input(buf
, 80)) ip
->i_nlinks
= atol(buf
);
691 printf(" size = %6ld", ip
->i_size
);
692 if (input(buf
, 80)) ip
->i_size
= atol(buf
);
693 if (yes("Write this back")) {
694 devwrite(inoblock(ino
), inooff(ino
), (char *) ip
,
698 } while (yes("Do you want to change it again"));
702 /* Allocate `nblk' blocks worth of bitmap. */
703 bitchunk_t
*allocbitmap(nblk
)
706 register bitchunk_t
*bitmap
;
708 bitmap
= (bitchunk_t
*) alloc((unsigned) nblk
, block_size
);
713 /* Load the bitmap starting at block `bno' from disk. */
714 void loadbitmap(bitmap
, bno
, nblk
)
720 register bitchunk_t
*p
;
723 for (i
= 0; i
< nblk
; i
++, bno
++, p
+= WORDS_PER_BLOCK
)
724 devread(bno
, 0, (char *) p
, block_size
);
728 /* Write the bitmap starting at block `bno' to disk. */
729 void dumpbitmap(bitmap
, bno
, nblk
)
735 register bitchunk_t
*p
= bitmap
;
737 for (i
= 0; i
< nblk
; i
++, bno
++, p
+= WORDS_PER_BLOCK
)
738 devwrite(bno
, 0, (char *) p
, block_size
);
741 /* Set the bits given by `list' in the bitmap. */
742 void fillbitmap(bitmap
, lwb
, upb
, list
)
749 if (list
== 0) return;
750 while ((bit
= getnumber(*list
++)) != NO_BIT
)
751 if (bit
< lwb
|| bit
>= upb
) {
752 if (bitmap
== spec_imap
)
753 printf("inode number %ld ", bit
);
755 printf("zone number %ld ", bit
);
756 printf("out of range (ignored)\n");
758 setbit(bitmap
, bit
- lwb
+ 1);
761 /* Deallocate the bitmap `p'. */
768 /* Get all the bitmaps used by this program. */
771 imap
= allocbitmap(N_IMAP
);
772 zmap
= allocbitmap(N_ZMAP
);
773 spec_imap
= allocbitmap(N_IMAP
);
774 spec_zmap
= allocbitmap(N_ZMAP
);
775 dirmap
= allocbitmap(N_IMAP
);
778 /* Release all the space taken by the bitmaps. */
783 freebitmap(spec_imap
);
784 freebitmap(spec_zmap
);
788 /* `w1' and `w2' are differing words from two bitmaps that should be
789 * identical. Print what's the matter with them.
791 void chkword(w1
, w2
, bit
, type
, n
, report
, phys
)
798 for (; (w1
| w2
); w1
>>= 1, w2
>>= 1, bit
++, phys
++)
799 if ((w1
^ w2
) & 1 && ++(*n
) % MAXPRINT
== 0 && *report
&&
800 (!repair
|| automatic
|| yes("stop this listing")))
803 if ((w1
& 1) && !(w2
& 1))
804 printf("%s %ld is missing\n", type
, bit
);
805 else if (!(w1
& 1) && (w2
& 1))
806 printf("%s %ld is not free\n", type
, bit
);
809 /* Check if the given (correct) bitmap is identical with the one that is
810 * on the disk. If not, ask if the disk should be repaired.
812 void chkmap(cmap
, dmap
, bit
, blkno
, nblk
, type
)
813 bitchunk_t
*cmap
, *dmap
;
819 register bitchunk_t
*p
= dmap
, *q
= cmap
;
820 int report
= 1, nerr
= 0;
821 int w
= nblk
* WORDS_PER_BLOCK
;
824 printf("Checking %s map. ", type
);
825 if(!preen
) printf("\n");
827 loadbitmap(dmap
, blkno
, nblk
);
829 if (*p
!= *q
) chkword(*p
, *q
, bit
, type
, &nerr
, &report
, phys
);
832 bit
+= 8 * sizeof(bitchunk_t
);
833 phys
+= 8 * sizeof(bitchunk_t
);
836 if ((!repair
|| automatic
) && !report
) printf("etc. ");
837 if (nerr
> MAXPRINT
|| nerr
> 10) printf("%d errors found. ", nerr
);
838 if (nerr
!= 0 && yes("install a new map")) dumpbitmap(cmap
, blkno
, nblk
);
839 if (nerr
> 0) printf("\n");
842 /* See if the inodes that aren't allocated are cleared. */
845 register ino_t ino
= 1;
848 printf("Checking inode list. ");
849 if(!preen
) printf("\n");
852 if (!bitset(imap
, (bit_nr
) ino
)) {
853 devread(inoblock(ino
), inooff(ino
), (char *) &mode
,
855 if (mode
!= I_NOT_ALLOC
) {
856 printf("mode inode %u not cleared", ino
);
857 if (yes(". clear")) devwrite(inoblock(ino
),
858 inooff(ino
), nullbuf
, INODE_SIZE
);
861 while (++ino
<= sb
.s_ninodes
&& ino
!= 0);
862 if(!preen
) printf("\n");
865 /* Allocate an array to maintain the inode reference counts in. */
868 count
= (nlink_t
*) alloc((unsigned) (sb
.s_ninodes
+ 1), sizeof(nlink_t
));
871 /* The reference count for inode `ino' is wrong. Ask if it should be adjusted. */
872 void counterror(ino_t ino
)
877 printf("INODE NLINK COUNT\n");
880 devread(inoblock(ino
), inooff(ino
), (char *) &inode
, INODE_SIZE
);
881 count
[ino
] += inode
.i_nlinks
; /* it was already subtracted; add it back */
882 printf("%5u %5u %5u", ino
, (unsigned) inode
.i_nlinks
, count
[ino
]);
883 if (yes(" adjust")) {
884 if ((inode
.i_nlinks
= count
[ino
]) == 0) {
885 fatal("internal error (counterror)");
886 inode
.i_mode
= I_NOT_ALLOC
;
887 clrbit(imap
, (bit_nr
) ino
);
889 devwrite(inoblock(ino
), inooff(ino
), (char *) &inode
, INODE_SIZE
);
893 /* Check if the reference count of the inodes are correct. The array `count'
894 * is maintained as follows: an entry indexed by the inode number is
895 * incremented each time a link is found; when the inode is read the link
896 * count in there is substracted from the corresponding entry in `count'.
897 * Thus, when the whole file system has been traversed, all the entries
904 for (ino
= 1; ino
<= sb
.s_ninodes
&& ino
!= 0; ino
++)
905 if (count
[ino
] != 0) counterror(ino
);
906 if (!firstcnterr
) printf("\n");
909 /* Deallocate the `count' array. */
912 free((char *) count
);
915 /* Print the inode permission bits given by mode and shift. */
916 void printperm(mode_t mode
, int shift
, int special
, int overlay
)
918 if (mode
>> shift
& R_BIT
)
922 if (mode
>> shift
& W_BIT
)
929 if (mode
>> shift
& X_BIT
)
935 /* List the given inode. */
936 void list(ino_t ino
, d_inode
*ip
)
940 printf(" inode permission link size name\n");
943 switch (ip
->i_mode
& I_TYPE
) {
944 case I_REGULAR
: putchar('-'); break;
945 case I_DIRECTORY
: putchar('d'); break;
946 case I_CHAR_SPECIAL
: putchar('c'); break;
947 case I_BLOCK_SPECIAL
: putchar('b'); break;
948 case I_NAMED_PIPE
: putchar('p'); break;
949 case I_UNIX_SOCKET
: putchar('s'); break;
950 #ifdef I_SYMBOLIC_LINK
951 case I_SYMBOLIC_LINK
: putchar('l'); break;
953 default: putchar('?');
955 printperm(ip
->i_mode
, 6, I_SET_UID_BIT
, 's');
956 printperm(ip
->i_mode
, 3, I_SET_GID_BIT
, 's');
957 printperm(ip
->i_mode
, 0, STICKY_BIT
, 't');
958 printf(" %3u ", ip
->i_nlinks
);
959 switch (ip
->i_mode
& I_TYPE
) {
961 case I_BLOCK_SPECIAL
:
962 printf(" %2x,%2x ", (dev_t
) ip
->i_zone
[0] >> MAJOR
& 0xFF,
963 (dev_t
) ip
->i_zone
[0] >> MINOR
& 0xFF);
965 default: printf("%7ld ", 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
, sizeof(dp
->mfs_d_name
));
1028 printf("bad %s in ", printable_name
);
1030 printf("%s is linked to %u ", printable_name
, dp
->d_inum
);
1031 printf("instead of %u)", exp
);
1032 setbit(spec_imap
, (bit_nr
) ino
);
1033 setbit(spec_imap
, (bit_nr
) dp
->d_inum
);
1034 setbit(spec_imap
, (bit_nr
) exp
);
1035 if (yes(". repair")) {
1036 count
[dp
->d_inum
]--;
1041 } else if (pos
!= (dp
->mfs_d_name
[1] ? DIR_ENTRY_SIZE
: 0)) {
1042 make_printable_name(printable_name
, dp
->mfs_d_name
, sizeof(dp
->mfs_d_name
));
1043 printf("warning: %s has offset %ld in ", printable_name
, pos
);
1045 printf("%s is linked to %u)\n", printable_name
, dp
->d_inum
);
1046 setbit(spec_imap
, (bit_nr
) ino
);
1047 setbit(spec_imap
, (bit_nr
) dp
->d_inum
);
1048 setbit(spec_imap
, (bit_nr
) exp
);
1053 /* Check the name in a directory entry. */
1054 int chkname(ino_t ino
, dir_struct
*dp
)
1056 register n
= MFS_NAME_MAX
+ 1;
1057 register char *p
= dp
->mfs_d_name
;
1060 printf("null name found in ");
1062 setbit(spec_imap
, (bit_nr
) ino
);
1063 if (Remove(dp
)) return(0);
1065 while (*p
!= '\0' && --n
!= 0)
1067 printf("found a '/' in entry of directory ");
1069 setbit(spec_imap
, (bit_nr
) ino
);
1070 printf("entry = '");
1071 printname(dp
->mfs_d_name
);
1073 if (Remove(dp
)) return(0);
1079 /* Check a directory entry. Here the routine `descendtree' is called
1080 * recursively to check the file or directory pointed to by the entry.
1082 int chkentry(ino_t ino
, off_t pos
, dir_struct
*dp
)
1084 if (dp
->d_inum
< ROOT_INODE
|| dp
->d_inum
> sb
.s_ninodes
) {
1085 printf("bad inode found in directory ");
1087 printf("ino found = %u, ", dp
->d_inum
);
1089 printname(dp
->mfs_d_name
);
1091 if (yes(". remove entry")) {
1092 memset((void *) dp
, 0, sizeof(dir_struct
));
1097 if ((unsigned) count
[dp
->d_inum
] == SHRT_MAX
) {
1098 printf("too many links to ino %u\n", dp
->d_inum
);
1099 printf("discovered at entry '");
1100 printname(dp
->mfs_d_name
);
1101 printf("' in directory ");
1103 if (Remove(dp
)) return(0);
1105 count
[dp
->d_inum
]++;
1106 if (strcmp(dp
->mfs_d_name
, ".") == 0) {
1107 ftop
->st_presence
|= DOT
;
1108 return(chkdots(ino
, pos
, dp
, ino
));
1110 if (strcmp(dp
->mfs_d_name
, "..") == 0) {
1111 ftop
->st_presence
|= DOTDOT
;
1112 return(chkdots(ino
, pos
, dp
, ino
== ROOT_INODE
? ino
:
1113 ftop
->st_next
->st_dir
->d_inum
));
1115 if (!chkname(ino
, dp
)) return(0);
1116 if (bitset(dirmap
, (bit_nr
) dp
->d_inum
)) {
1117 printf("link to directory discovered in ");
1120 printname(dp
->mfs_d_name
);
1121 printf("', dir ino = %u)", dp
->d_inum
);
1124 return(descendtree(dp
));
1127 /* Check a zone of a directory by checking all the entries in the zone.
1128 * The zone is split up into chunks to not allocate too much stack.
1130 int chkdirzone(ino_t ino
, d_inode
*ip
, off_t pos
, zone_nr zno
)
1132 dir_struct dirblk
[CDIRECT
];
1133 register dir_struct
*dp
;
1135 long block
= ztob(zno
);
1136 register long offset
= 0;
1137 register off_t size
= 0;
1138 n
= SCALE
* (NR_DIR_ENTRIES(block_size
) / CDIRECT
);
1141 devread(block
, offset
, (char *) dirblk
, DIRCHUNK
);
1143 for (dp
= dirblk
; dp
< &dirblk
[CDIRECT
]; dp
++) {
1144 if (dp
->d_inum
!= NO_ENTRY
&& !chkentry(ino
, pos
, dp
))
1146 pos
+= DIR_ENTRY_SIZE
;
1147 if (dp
->d_inum
!= NO_ENTRY
) size
= pos
;
1149 if (dirty
) devwrite(block
, offset
, (char *) dirblk
, DIRCHUNK
);
1154 if (size
> ip
->i_size
) {
1155 printf("size not updated of directory ");
1157 if (yes(". extend")) {
1158 setbit(spec_imap
, (bit_nr
) ino
);
1160 devwrite(inoblock(ino
), inooff(ino
), (char *) ip
, INODE_SIZE
);
1167 int chksymlinkzone(ino_t ino
, d_inode
*ip
, off_t pos
, zone_nr zno
)
1171 char target
[PATH_MAX
+1];
1173 if (ip
->i_size
> PATH_MAX
)
1174 fatal("chksymlinkzone: fsck program inconsistency\n");
1176 devread(block
, 0, target
, ip
->i_size
);
1177 target
[ip
->i_size
]= '\0';
1178 len
= strlen(target
);
1179 if (len
!= ip
->i_size
)
1181 printf("bad size in symbolic link (%d instead of %d) ",
1184 if (yes(". update")) {
1185 setbit(spec_imap
, (bit_nr
) ino
);
1187 devwrite(inoblock(ino
), inooff(ino
),
1188 (char *) ip
, INODE_SIZE
);
1194 /* There is something wrong with the given zone. Print some details. */
1195 void errzone(mess
, zno
, level
, pos
)
1201 printf("%s zone in ", mess
);
1203 printf("zno = %ld, type = ", zno
);
1205 case 0: printf("DATA"); break;
1206 case 1: printf("SINGLE INDIRECT"); break;
1207 case 2: printf("DOUBLE INDIRECT"); break;
1208 default: printf("VERY INDIRECT");
1210 printf(", pos = %ld)\n", pos
);
1213 /* Found the given zone in the given inode. Check it, and if ok, mark it
1214 * in the zone bitmap.
1216 int markzone(zno
, level
, pos
)
1221 register bit_nr bit
= (bit_nr
) zno
- FIRST
+ 1;
1224 if (zno
< FIRST
|| zno
>= sb
.s_zones
) {
1225 errzone("out-of-range", zno
, level
, pos
);
1228 if (bitset(zmap
, bit
)) {
1229 setbit(spec_zmap
, bit
);
1230 errzone("duplicate", zno
, level
, pos
);
1234 if (bitset(spec_zmap
, bit
)) errzone("found", zno
, level
, pos
);
1239 /* Check an indirect zone by checking all of its entries.
1240 * The zone is split up into chunks to not allocate too much stack.
1242 int chkindzone(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr zno
, int level
)
1244 zone_nr indirect
[CINDIR
];
1245 register n
= NR_INDIRECTS
/ CINDIR
;
1246 long block
= ztob(zno
);
1247 register long offset
= 0;
1250 devread(block
, offset
, (char *) indirect
, INDCHUNK
);
1251 if (!chkzones(ino
, ip
, pos
, indirect
, CINDIR
, level
- 1)) return(0);
1253 } while (--n
&& *pos
< ip
->i_size
);
1257 /* Return the size of a gap in the file, represented by a null zone number
1258 * at some level of indirection.
1263 off_t power
= ZONE_SIZE
;
1266 power
*= NR_INDIRECTS
;
1271 /* Check a zone, which may be either a normal data zone, a directory zone,
1272 * or an indirect zone.
1274 int zonechk(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr zno
, int level
)
1277 if ((ip
->i_mode
& I_TYPE
) == I_DIRECTORY
&&
1278 !chkdirzone(ino
, ip
, *pos
, zno
))
1280 if ((ip
->i_mode
& I_TYPE
) == I_SYMBOLIC_LINK
&&
1281 !chksymlinkzone(ino
, ip
, *pos
, zno
))
1286 return chkindzone(ino
, ip
, pos
, zno
, level
);
1289 /* Check a list of zones given by `zlist'. */
1290 int chkzones(ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr
*zlist
,
1295 /* The check on the position in the next loop is commented out, since FS
1296 * now requires valid zone numbers in each level that is necessary and FS
1297 * always deleted all the zones in the double indirect block.
1299 for (i
= 0; i
< len
/* && *pos < ip->i_size */ ; i
++)
1300 if (zlist
[i
] == NO_ZONE
)
1301 *pos
+= jump(level
);
1302 else if (!markzone(zlist
[i
], level
, *pos
)) {
1303 *pos
+= jump(level
);
1305 } else if (!zonechk(ino
, ip
, pos
, zlist
[i
], level
))
1310 /* Check a file or a directory. */
1311 int chkfile(ino_t ino
, d_inode
*ip
)
1313 register ok
, i
, level
;
1316 ok
= chkzones(ino
, ip
, &pos
, &ip
->i_zone
[0], NR_DZONE_NUM
, 0);
1317 for (i
= NR_DZONE_NUM
, level
= 1; i
< NR_ZONE_NUMS
; i
++, level
++)
1318 ok
&= chkzones(ino
, ip
, &pos
, &ip
->i_zone
[i
], 1, level
);
1322 /* Check a directory by checking the contents. Check if . and .. are present. */
1323 int chkdirectory(ino_t ino
, d_inode
*ip
)
1327 setbit(dirmap
, (bit_nr
) ino
);
1328 ok
= chkfile(ino
, ip
);
1329 if (!(ftop
->st_presence
& DOT
)) {
1330 printf(". missing in ");
1334 if (!(ftop
->st_presence
& DOTDOT
)) {
1335 printf(".. missing in ");
1342 #ifdef I_SYMBOLIC_LINK
1344 /* Check the validity of a symbolic link. */
1345 int chklink(ino_t ino
, d_inode
*ip
)
1349 ok
= chkfile(ino
, ip
);
1350 if (ip
->i_size
<= 0 || ip
->i_size
> block_size
) {
1351 if (ip
->i_size
== 0)
1352 printf("empty symbolic link ");
1354 printf("symbolic link too large (size %ld) ", ip
->i_size
);
1363 /* Check the validity of a special file. */
1364 int chkspecial(ino_t ino
, d_inode
*ip
)
1369 if ((dev_t
) ip
->i_zone
[0] == NO_DEV
) {
1370 printf("illegal device number %ld for special file ", ip
->i_zone
[0]);
1375 /* FS will not use the remaining "zone numbers" but 1.6.11++ will panic if
1376 * they are nonzero, since this should not happen.
1378 for (i
= 1; i
< NR_ZONE_NUMS
; i
++)
1379 if (ip
->i_zone
[i
] != NO_ZONE
) {
1380 printf("nonzero zone number %ld for special file ",
1388 /* Check the mode and contents of an inode. */
1389 int chkmode(ino_t ino
, d_inode
*ip
)
1391 switch (ip
->i_mode
& I_TYPE
) {
1394 return chkfile(ino
, ip
);
1397 return chkdirectory(ino
, ip
);
1398 case I_BLOCK_SPECIAL
:
1400 return chkspecial(ino
, ip
);
1401 case I_CHAR_SPECIAL
:
1403 return chkspecial(ino
, ip
);
1406 return chkfile(ino
, ip
);
1409 return chkfile(ino
, ip
);
1410 #ifdef I_SYMBOLIC_LINK
1411 case I_SYMBOLIC_LINK
:
1413 return chklink(ino
, ip
);
1417 printf("bad mode of ");
1419 printf("mode = %o)", ip
->i_mode
);
1424 /* Check an inode. */
1425 int chkinode(ino_t ino
, d_inode
*ip
)
1427 if (ino
== ROOT_INODE
&& (ip
->i_mode
& I_TYPE
) != I_DIRECTORY
) {
1428 printf("root inode is not a directory ");
1429 printf("(ino = %u, mode = %o)\n", ino
, ip
->i_mode
);
1432 if (ip
->i_nlinks
== 0) {
1433 printf("link count zero of ");
1438 setbit(imap
, (bit_nr
) ino
);
1439 if ((unsigned) ip
->i_nlinks
> SHRT_MAX
) {
1440 printf("link count too big in ");
1442 printf("cnt = %u)\n", (unsigned) ip
->i_nlinks
);
1443 count
[ino
] -= SHRT_MAX
;
1444 setbit(spec_imap
, (bit_nr
) ino
);
1446 count
[ino
] -= (unsigned) ip
->i_nlinks
;
1448 return chkmode(ino
, ip
);
1451 /* Check the directory entry pointed to by dp, by checking the inode. */
1456 register ino_t ino
= dp
->d_inum
;
1463 if (bitset(spec_imap
, (bit_nr
) ino
)) {
1464 printf("found inode %u: ", ino
);
1467 visited
= bitset(imap
, (bit_nr
) ino
);
1468 if (!visited
|| listing
) {
1469 devread(inoblock(ino
), inooff(ino
), (char *) &inode
, INODE_SIZE
);
1470 if (listing
) list(ino
, &inode
);
1471 if (!visited
&& !chkinode(ino
, &inode
)) {
1472 setbit(spec_imap
, (bit_nr
) ino
);
1473 if (yes("remove")) {
1474 count
[ino
] += inode
.i_nlinks
- 1;
1475 clrbit(imap
, (bit_nr
) ino
);
1476 devwrite(inoblock(ino
), inooff(ino
),
1477 nullbuf
, INODE_SIZE
);
1478 memset((void *) dp
, 0, sizeof(dir_struct
));
1479 ftop
= ftop
->st_next
;
1484 ftop
= ftop
->st_next
;
1488 /* Check the file system tree. */
1493 nfreeinode
= sb
.s_ninodes
;
1495 dir
.d_inum
= ROOT_INODE
;
1496 dir
.mfs_d_name
[0] = 0;
1497 if (!descendtree(&dir
)) fatal("bad root inode");
1501 /* Print the totals of all the objects found. */
1505 printf("%d files, %d directories, %d free inodes, %d free zones\n",
1506 nregular
, ndirectory
, nfreeinode
, nfreezone
);
1510 printf("blocksize = %5d ", block_size
);
1511 printf("zonesize = %5d\n", ZONE_SIZE
);
1513 pr("%8u Regular file%s\n", nregular
, "", "s");
1514 pr("%8u Director%s\n", ndirectory
, "y", "ies");
1515 pr("%8u Block special file%s\n", nblkspec
, "", "s");
1516 pr("%8u Character special file%s\n", ncharspec
, "", "s");
1517 if (nbadinode
!= 0) pr("%6u Bad inode%s\n", nbadinode
, "", "s");
1518 pr("%8u Free inode%s\n", nfreeinode
, "", "s");
1519 pr("%8u Named pipe%s\n", npipe
, "", "s");
1520 pr("%8u Unix socket%s\n", nsock
, "", "s");
1521 pr("%8u Symbolic link%s\n", nsyml
, "", "s");
1522 /* Don't print some fields.
1524 pr("%8u Data zone%s\n", ztype[0], "", "s");
1525 pr("%8u Single indirect zone%s\n", ztype[1], "", "s");
1526 pr("%8u Double indirect zone%s\n", ztype[2], "", "s");
1528 lpr("%8ld Free zone%s\n", nfreezone
, "", "s");
1531 /* Check the device which name is given by `f'. The inodes listed by `clist'
1532 * should be listed separately, and the inodes listed by `ilist' and the zones
1533 * listed by `zlist' should be watched for while checking the file system.
1536 void chkdev(f
, clist
, ilist
, zlist
)
1537 char *f
, **clist
, **ilist
, **zlist
;
1539 if (automatic
) repair
= 1;
1545 rw_super(SUPER_GET
);
1547 if(block_size
< _MIN_BLOCK_SIZE
)
1548 fatal("funny block size");
1550 if(!(rwbuf
= malloc(block_size
))) fatal("couldn't allocate fs buf (1)");
1551 if(!(nullbuf
= malloc(block_size
))) fatal("couldn't allocate fs buf (2)");
1552 memset(nullbuf
, 0, block_size
);
1557 if(sb
.s_flags
& MFSFLAG_CLEAN
) {
1558 sb
.s_flags
&= ~MFSFLAG_CLEAN
;
1559 rw_super(SUPER_PUT
);
1560 printf("\n----- FILE SYSTEM MARKED DIRTY -----\n\n");
1562 printf("Filesystem is already dirty.\n");
1566 /* If preening, skip fsck if clean flag is on. */
1568 if(sb
.s_flags
& MFSFLAG_CLEAN
) {
1569 printf("%s: clean\n", f
);
1572 printf("%s: dirty, performing fsck\n", f
);
1579 fillbitmap(spec_imap
, (bit_nr
) 1, (bit_nr
) sb
.s_ninodes
+ 1, ilist
);
1580 fillbitmap(spec_zmap
, (bit_nr
) FIRST
, (bit_nr
) sb
.s_zones
, zlist
);
1584 chkmap(zmap
, spec_zmap
, (bit_nr
) FIRST
- 1, BLK_ZMAP
, N_ZMAP
, "zone");
1586 chkmap(imap
, spec_imap
, (bit_nr
) 0, BLK_IMAP
, N_IMAP
, "inode");
1588 if(preen
) printf("\n");
1594 if (changed
) printf("\n----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
1596 /* If we were told to repair the FS, and the user never stopped us from
1597 * doing it, and the FS wasn't marked clean, we can mark the FS as clean.
1598 * If we were stopped from repairing, tell user about it.
1600 if(repair
&& !(sb
.s_flags
& MFSFLAG_CLEAN
)) {
1602 printf("\n----- FILE SYSTEM STILL DIRTY -----\n\n");
1604 sync(); /* update FS on disk before clean flag */
1605 sb
.s_flags
|= MFSFLAG_CLEAN
;
1606 rw_super(SUPER_PUT
);
1607 printf("\n----- FILE SYSTEM MARKED CLEAN -----\n\n");
1614 int main(argc
, argv
)
1618 register char **clist
= 0, **ilist
= 0, **zlist
= 0;
1621 register devgiven
= 0;
1624 if ((1 << BITSHIFT
) != 8 * sizeof(bitchunk_t
)) {
1625 printf("Fsck was compiled with the wrong BITSHIFT!\n");
1626 exit(FSCK_EXIT_CHECK_FAILED
);
1631 while ((arg
= *argv
++) != 0)
1632 if (arg
[0] == '-' && arg
[1] != 0 && arg
[2] == 0) switch (arg
[1]) {
1633 case 'd': markdirty
= 1; break;
1634 case 'p': preen
= repair
= automatic
= 1; break;
1636 case 'a': automatic
^= 1; break;
1638 clist
= getlist(&argv
, "inode");
1641 ilist
= getlist(&argv
, "inode");
1644 zlist
= getlist(&argv
, "zone");
1646 case 'r': repair
^= 1; break;
1647 case 'l': listing
^= 1; break;
1648 case 's': listsuper
^= 1; break;
1651 printf("%s: unknown flag '%s'\n", prog
, arg
);
1655 chkdev(arg
, clist
, ilist
, zlist
);
1661 if (!devgiven
|| badflag
) {
1662 printf("Usage: fsck [-dyfpacilrsz] file\n");
1663 exit(FSCK_EXIT_USAGE
);