1 /* Hacks for version 1.6 */
3 #define INODES_PER_BLOCK V1_INODES_PER_BLOCK
4 #define INODE_SIZE V1_INODE_SIZE
5 #define WORDS_PER_BLOCK (BLOCK_SIZE / (int) sizeof(bitchunk_t))
6 #define MAX_ZONES (V1_NR_DZONES+V1_INDIRECTS+(long)V1_INDIRECTS*V1_INDIRECTS)
7 #define NR_DZONE_NUM V1_NR_DZONES
8 #define NR_INDIRECTS V1_INDIRECTS
9 #define NR_ZONE_NUMS V1_NR_TZONES
10 #define ZONE_NUM_SIZE V1_ZONE_NUM_SIZE
11 #define bit_nr u16_t /* perhaps bit_t should be used, although slower */
13 #define block_nr block_t
14 #define d_inode d1_inode
16 #define dir_struct struct direct
17 #define i_mode d1_mode
18 #define i_nlinks d1_nlinks
19 #define i_size d1_size
20 #define i_zone d1_zone
21 #define zone_nr zone1_t
22 #define Zone_nr Zone1_t
24 /* fsck - file system checker Author: Robbert van Renesse */
26 /* Modified by Norbert Schlenker
27 * Removed vestiges of standalone/DOS versions:
28 * - various unused variables and buffers removed
29 * - now uses library functions rather than private internal routines
30 * - bytewise structure copies replaced by structure assignment
31 * - fixed one bug with 14 character file names
32 * - other small tweaks for speed
34 * Modified by Lars Fredriksen at the request of Andy Tanenbaum, 90-03-10.
35 * Removed -m option, by which fsck could be told to make a file
36 * system on a 360K floppy. The code had limited utility, was buggy,
37 * and failed due to a bug in the ACK C compiler. Use mkfs instead!
40 #include <sys/types.h>
49 #include <minix/config.h>
50 #include <minix/const.h>
51 #include <minix/type.h>
52 #include "../../servers/mfs/const.h"
53 #include "../../servers/mfs/inode.h"
54 #include "../../servers/mfs/type.h"
55 #include <minix/fslib.h>
59 #define BLOCK_SIZE _STATIC_BLOCK_SIZE
61 #define BITSHIFT 4 /* = log2(#bits(int)) */
63 #define MAXPRINT 8 /* max. number of error lines in chkmap */
64 #define CINDIR 128 /* number of indirect zno's read at a time */
65 #define CDIRECT 16 /* number of dir entries read at a time */
66 #define BITMASK ((1 << BITSHIFT) - 1)
67 #define setbit(w, b) (w[(b) >> BITSHIFT] |= 1 << ((b) & BITMASK))
68 #define clrbit(w, b) (w[(b) >> BITSHIFT] &= ~(1 << ((b) & BITMASK)))
69 #define bitset(w, b) (w[(b) >> BITSHIFT] & (1 << ((b) & BITMASK)))
71 #define ZONE_CT 360 /* default zones (when making file system) */
72 #define INODE_CT 95 /* default inodes (when making file system) */
74 #include "../../servers/mfs/super.h"
75 struct super_block sb
;
77 #define STICKY_BIT 01000 /* not defined anywhere else */
79 /* Ztob gives the block address of a zone
80 * btoa gives the byte address of a block
82 #define ztob(z) ((block_nr) (z) << sb.s_log_zone_size)
83 #define btoa(b) ((long) (b) * BLOCK_SIZE)
84 #define SCALE ((int) ztob(1)) /* # blocks in a zone */
85 #define FIRST ((zone_nr) sb.s_firstdatazone) /* as the name says */
87 /* # blocks of each type */
89 #define N_IMAP (sb.s_imap_blocks)
90 #define N_ZMAP (sb.s_zmap_blocks)
91 #define N_ILIST ((sb.s_ninodes+INODES_PER_BLOCK-1) / INODES_PER_BLOCK)
92 #define N_DATA (sb.s_nzones - FIRST)
94 /* Block address of each type */
96 #define BLK_IMAP (BLK_SUPER + N_SUPER)
97 #define BLK_ZMAP (BLK_IMAP + N_IMAP)
98 #define BLK_ILIST (BLK_ZMAP + N_ZMAP)
99 #define BLK_FIRST ztob(FIRST)
100 #define ZONE_SIZE ((int) ztob(BLOCK_SIZE))
101 #define NLEVEL (NR_ZONE_NUMS - NR_DZONE_NUM + 1)
103 /* Byte address of a zone/of an inode */
104 #define zaddr(z) btoa(ztob(z))
105 #define inoaddr(i) ((long) (i - 1) * INODE_SIZE + btoa(BLK_ILIST))
106 #define INDCHUNK (CINDIR * ZONE_NUM_SIZE)
107 #define DIRCHUNK (CDIRECT * DIR_ENTRY_SIZE)
109 char *prog
, *device
; /* program name (fsck), device name */
110 int firstcnterr
; /* is this the first inode ref cnt error? */
111 bitchunk_t
*imap
, *spec_imap
; /* inode bit maps */
112 bitchunk_t
*zmap
, *spec_zmap
; /* zone bit maps */
113 bitchunk_t
*dirmap
; /* directory (inode) bit map */
114 char rwbuf
[BLOCK_SIZE
]; /* one block buffer cache */
115 block_nr thisblk
; /* block in buffer cache */
116 char nullbuf
[BLOCK_SIZE
]; /* null buffer */
117 nlink_t
*count
; /* inode count */
118 int changed
; /* has the diskette been written to? */
121 struct stack
*st_next
;
125 int dev
; /* file descriptor of the device */
130 /* Counters for each type of inode/zone. */
131 int nfreeinode
, nregular
, ndirectory
, nblkspec
, ncharspec
, nbadinode
;
132 int npipe
, nsyml
, nfreezone
, ztype
[NLEVEL
];
134 int repair
, automatic
, listing
, listsuper
; /* flags */
135 int firstlist
; /* has the listing header been printed? */
136 unsigned part_offset
; /* sector offset for this partition */
137 char answer
[] = "Answer questions with y or n. Then hit RETURN";
139 _PROTOTYPE(int main
, (int argc
, char **argv
));
140 _PROTOTYPE(void initvars
, (void));
141 _PROTOTYPE(void fatal
, (char *s
));
142 _PROTOTYPE(int eoln
, (int c
));
143 _PROTOTYPE(int yes
, (char *question
));
144 _PROTOTYPE(int atoo
, (char *s
));
145 _PROTOTYPE(int input
, (char *buf
, int size
));
146 _PROTOTYPE(char *alloc
, (unsigned nelem
, unsigned elsize
));
147 _PROTOTYPE(void printname
, (char *s
));
148 _PROTOTYPE(void printrec
, (struct stack
*sp
));
149 _PROTOTYPE(void printpath
, (int mode
, int nlcr
));
150 _PROTOTYPE(void devopen
, (void));
151 _PROTOTYPE(void devclose
, (void));
152 _PROTOTYPE(void devio
, (block_nr bno
, int dir
));
153 _PROTOTYPE(void devread
, (long offset
, char *buf
, int size
));
154 _PROTOTYPE(void devwrite
, (long offset
, char *buf
, int size
));
155 _PROTOTYPE(void pr
, (char *fmt
, int cnt
, char *s
, char *p
));
156 _PROTOTYPE(bit_nr getnumber
, (char *s
));
157 _PROTOTYPE(char **getlist
, (char ***argv
, char *type
));
158 _PROTOTYPE(void lsuper
, (void));
159 _PROTOTYPE(void getsuper
, (void));
160 _PROTOTYPE(void chksuper
, (void));
161 _PROTOTYPE(void lsi
, (char **clist
));
162 _PROTOTYPE(bitchunk_t
*allocbitmap
, (int nblk
));
163 _PROTOTYPE(void loadbitmap
, (bitchunk_t
*bitmap
, block_nr bno
, int nblk
));
164 _PROTOTYPE(void dumpbitmap
, (bitchunk_t
*bitmap
, block_nr bno
, int nblk
));
165 _PROTOTYPE(void fillbitmap
, (bitchunk_t
*bitmap
, Bit_nr lwb
, Bit_nr upb
, char **list
));
166 _PROTOTYPE(void freebitmap
, (bitchunk_t
*p
));
167 _PROTOTYPE(void getbitmaps
, (void));
168 _PROTOTYPE(void putbitmaps
, (void));
169 _PROTOTYPE(void chkword
, (unsigned w1
, unsigned w2
, Bit_nr bit
, char *type
, int *n
, int *report
));
170 _PROTOTYPE(void chkmap
, (bitchunk_t
*cmap
, bitchunk_t
*dmap
, Bit_nr bit
, block_nr blkno
, int nblk
, char *type
));
171 _PROTOTYPE(void chkilist
, (void));
172 _PROTOTYPE(void getcount
, (void));
173 _PROTOTYPE(void counterror
, (Ino_t ino
));
174 _PROTOTYPE(void chkcount
, (void));
175 _PROTOTYPE(void freecount
, (void));
176 _PROTOTYPE(void printperm
, (mode_t mode
, int shift
, int special
, int overlay
));
177 _PROTOTYPE(void list
, (Ino_t ino
, d_inode
*ip
));
178 _PROTOTYPE(int Remove
, (dir_struct
*dp
));
179 _PROTOTYPE(void make_printable_name
, (char *dst
, char *src
, int n
));
180 _PROTOTYPE(int chkdots
, (Ino_t ino
, off_t pos
, dir_struct
*dp
, Ino_t exp
));
181 _PROTOTYPE(int chkname
, (Ino_t ino
, dir_struct
*dp
));
182 _PROTOTYPE(int chkentry
, (Ino_t ino
, off_t pos
, dir_struct
*dp
));
183 _PROTOTYPE(int chkdirzone
, (Ino_t ino
, d_inode
*ip
, off_t pos
, Zone_nr zno
));
184 _PROTOTYPE(void errzone
, (char *mess
, Zone_nr zno
, int level
, off_t pos
));
185 _PROTOTYPE(int markzone
, (Ino_t ino
, Zone_nr zno
, int level
, off_t pos
));
186 _PROTOTYPE(int chkindzone
, (Ino_t ino
, d_inode
*ip
, off_t
*pos
, Zone_nr zno
, int level
));
187 _PROTOTYPE(off_t jump
, (int level
));
188 _PROTOTYPE(int zonechk
, (Ino_t ino
, d_inode
*ip
, off_t
*pos
, Zone_nr zno
, int level
));
189 _PROTOTYPE(int chkzones
, (Ino_t ino
, d_inode
*ip
, off_t
*pos
, zone_nr
*zlist
, int len
, int level
));
190 _PROTOTYPE(int chkfile
, (Ino_t ino
, d_inode
*ip
));
191 _PROTOTYPE(int chkdirectory
, (Ino_t ino
, d_inode
*ip
));
192 _PROTOTYPE(int chklink
, (Ino_t ino
, d_inode
*ip
));
193 _PROTOTYPE(int chkmode
, (Ino_t ino
, d_inode
*ip
));
194 _PROTOTYPE(int chkinode
, (Ino_t ino
, d_inode
*ip
));
195 _PROTOTYPE(int chkspecial
, (Ino_t ino
, d_inode
*ip
) );
196 _PROTOTYPE(int descendtree
, (dir_struct
*dp
));
197 _PROTOTYPE(void chktree
, (void));
198 _PROTOTYPE(void printtotal
, (void));
199 _PROTOTYPE(void chkdev
, (char *f
, char **clist
, char **ilist
, char **zlist
));
201 /* Initialize the variables used by this program. */
206 nregular
= ndirectory
= nblkspec
= ncharspec
= nbadinode
= npipe
= nsyml
= 0;
207 for (level
= 0; level
< NLEVEL
; level
++) ztype
[level
] = 0;
214 /* Print the string `s' and exit. */
218 printf("%s\nfatal\n", s
);
222 /* Test for end of line. */
226 return(c
== EOF
|| c
== '\n' || c
== '\r');
229 /* Ask a question and get the answer unless automatic is set. */
239 printf("%s? ", question
);
245 if ((c
= answer
= getchar()) == 'q' || c
== 'Q') exit(1);
246 while (!eoln(c
)) c
= getchar();
247 return !(answer
== 'n' || answer
== 'N');
250 /* Convert string to integer. Representation is octal. */
256 while ('0' <= *s
&& *s
< '8') {
263 /* If repairing the file system, print a prompt and get a string from user. */
268 register char *p
= buf
;
283 while (!eoln(getchar()));
289 /* Allocate some memory and zero it. */
290 char *alloc(nelem
, elsize
)
291 unsigned nelem
, elsize
;
295 if ((p
= (char *) malloc((size_t)nelem
* elsize
)) == 0) fatal("out of memory");
296 memset(p
, 0, (size_t)nelem
* elsize
);
300 /* Print the name in a directory entry. */
304 register n
= NAME_MAX
;
308 if ((c
= *s
) == 0) break;
309 if (!isprint(c
)) c
= '?';
315 /* Print the pathname given by a linked list pointed to by `sp'. The
316 * names are in reverse order.
321 if (sp
->st_next
!= 0) {
322 printrec(sp
->st_next
);
324 printname(sp
->st_dir
->d_name
);
328 /* Print the current pathname. */
329 void printpath(mode
, nlcr
)
333 if (ftop
->st_next
== 0)
339 printf(" (ino = %u, ", ftop
->st_dir
->d_inum
);
342 printf(" (ino = %u)", ftop
->st_dir
->d_inum
);
345 if (nlcr
) printf("\n");
348 /* Open the device. */
351 if ((dev
= open(device
, repair
? O_RDWR
: O_RDONLY
)) < 0) {
357 /* Close the device. */
360 if (close(dev
) != 0) {
366 /* Read or write a block. */
371 if (dir
== READING
&& bno
== thisblk
) return;
374 lseek(dev
, (off_t
) btoa(bno
), SEEK_SET
);
375 if (dir
== READING
) {
376 if (read(dev
, rwbuf
, BLOCK_SIZE
) == BLOCK_SIZE
)
379 if (write(dev
, rwbuf
, BLOCK_SIZE
) == BLOCK_SIZE
)
383 printf("%s: can't %s block %ld (error = 0x%x)\n", prog
,
384 dir
== READING
? "read" : "write", (long) bno
, errno
);
385 if (dir
== READING
) {
386 printf("Continuing with a zero-filled block.\n");
387 memset(rwbuf
, 0, BLOCK_SIZE
);
393 /* Read `size' bytes from the disk starting at byte `offset'. */
394 void devread(offset
, buf
, size
)
399 devio((block_nr
) (offset
/ BLOCK_SIZE
), READING
);
400 memmove(buf
, &rwbuf
[(int) (offset
% BLOCK_SIZE
)], (size_t)size
);
403 /* Write `size' bytes to the disk starting at byte `offset'. */
404 void devwrite(offset
, buf
, size
)
409 if (!repair
) fatal("internal error (devwrite)");
410 if (size
!= BLOCK_SIZE
) devio((block_nr
) (offset
/ BLOCK_SIZE
), READING
);
411 memmove(&rwbuf
[(int) (offset
% BLOCK_SIZE
)], buf
, (size_t)size
);
412 devio((block_nr
) (offset
/ BLOCK_SIZE
), WRITING
);
416 /* Print a string with either a singular or a plural pronoun. */
417 void pr(fmt
, cnt
, s
, p
)
421 printf(fmt
, cnt
, cnt
== 1 ? s
: p
);
424 /* Convert string to number. */
428 register bit_nr n
= 0;
433 n
= (n
<< 1) + (n
<< 3) + *s
++ - '0';
434 return (*s
== '\0') ? n
: NO_BIT
;
437 /* See if the list pointed to by `argv' contains numbers. */
438 char **getlist(argv
, type
)
441 register char **list
= *argv
;
444 while (getnumber(**argv
) != NO_BIT
) {
449 printf("warning: no %s numbers given\n", type
);
455 /* Make a listing of the super block. If `repair' is set, ask the user
463 printf("ninodes = %u", sb
.s_ninodes
);
464 if (input(buf
, 80)) sb
.s_ninodes
= atol(buf
);
465 printf("nzones = %u", sb
.s_nzones
);
466 if (input(buf
, 80)) sb
.s_nzones
= atol(buf
);
467 printf("imap_blocks = %u", sb
.s_imap_blocks
);
468 if (input(buf
, 80)) sb
.s_imap_blocks
= atol(buf
);
469 printf("zmap_blocks = %u", sb
.s_zmap_blocks
);
470 if (input(buf
, 80)) sb
.s_zmap_blocks
= atol(buf
);
471 printf("firstdatazone = %u", sb
.s_firstdatazone
);
472 if (input(buf
, 80)) sb
.s_firstdatazone
= atol(buf
);
473 printf("log_zone_size = %u", sb
.s_log_zone_size
);
474 if (input(buf
, 80)) sb
.s_log_zone_size
= atol(buf
);
475 printf("maxsize = %lu", sb
.s_max_size
);
476 if (input(buf
, 80)) sb
.s_max_size
= atol(buf
);
478 devwrite(btoa(BLK_SUPER
), (char *) &sb
, sizeof(sb
));
481 } while (yes("Do you want to try again"));
485 /* Get the super block from either disk or user. Do some initial checks. */
488 devread(btoa(BLK_SUPER
), (char *) &sb
, sizeof(sb
));
489 if (listsuper
) lsuper();
490 if (sb
.s_magic
== SUPER_V2
) fatal("Cannot handle V2 file systems");
491 if (sb
.s_magic
!= SUPER_MAGIC
) fatal("bad magic number in super block");
492 if ((short) sb
.s_ninodes
<= 0) fatal("no inodes");
493 if (sb
.s_nzones
<= 2) fatal("no zones");
494 if ((short) sb
.s_imap_blocks
<= 0) fatal("no imap");
495 if ((short) sb
.s_zmap_blocks
<= 0) fatal("no zmap");
496 if ((short) sb
.s_firstdatazone
<= 1) fatal("first data zone too small");
497 if ((short) sb
.s_log_zone_size
< 0) fatal("zone size < block size");
498 if (sb
.s_max_size
<= 0) fatal("max. file size <= 0");
501 /* Check the super block for reasonable contents. */
505 register off_t maxsize
;
507 n
= bitmapsize((bit_t
) sb
.s_ninodes
+ 1, BLOCK_SIZE
);
508 if (sb
.s_magic
!= SUPER_MAGIC
) fatal("bad magic number in super block");
509 if ((short) sb
.s_imap_blocks
< n
) fatal("too few imap blocks");
510 if (sb
.s_imap_blocks
!= n
) {
511 pr("warning: expected %d imap_block%s", n
, "", "s");
512 printf(" instead of %d\n", sb
.s_imap_blocks
);
514 n
= bitmapsize((bit_t
) sb
.s_nzones
, BLOCK_SIZE
);
515 if ((short) sb
.s_zmap_blocks
< n
) fatal("too few zmap blocks");
516 if (sb
.s_zmap_blocks
!= n
) {
517 pr("warning: expected %d zmap_block%s", n
, "", "s");
518 printf(" instead of %d\n", sb
.s_zmap_blocks
);
520 if (sb
.s_firstdatazone
>= sb
.s_nzones
)
521 fatal("first data zone too large");
522 if ((unsigned short) sb
.s_log_zone_size
>= 8 * sizeof(block_nr
))
523 fatal("log_zone_size too large");
524 if (sb
.s_log_zone_size
> 8) printf("warning: large log_zone_size (%d)\n",
526 n
= (BLK_ILIST
+ N_ILIST
+ SCALE
- 1) >> sb
.s_log_zone_size
;
527 if ((short) sb
.s_firstdatazone
< n
) fatal("first data zone too small");
528 if (sb
.s_firstdatazone
!= n
) {
529 printf("warning: expected first data zone to be %d ", n
);
530 printf("instead of %u\n", sb
.s_firstdatazone
);
532 maxsize
= MAX_FILE_POS
;
533 if (((maxsize
- 1) >> sb
.s_log_zone_size
) / BLOCK_SIZE
>= MAX_ZONES
)
534 maxsize
= ((long) MAX_ZONES
* BLOCK_SIZE
) << sb
.s_log_zone_size
;
535 if (sb
.s_max_size
!= maxsize
) {
536 printf("warning: expected max size to be %ld ", maxsize
);
537 printf("instead of %ld\n", sb
.s_max_size
);
541 /* Make a listing of the inodes given by `clist'. If `repair' is set, ask
542 * the user for changes.
549 d_inode inode
, *ip
= &inode
;
552 if (clist
== 0) return;
553 while ((bit
= getnumber(*clist
++)) != NO_BIT
) {
554 setbit(spec_imap
, bit
);
557 devread(inoaddr(ino
), (char *) ip
, INODE_SIZE
);
558 printf("inode %u:\n", ino
);
559 printf(" mode = %06o", ip
->i_mode
);
560 if (input(buf
, 80)) ip
->i_mode
= atoo(buf
);
561 printf(" nlinks = %6u", ip
->i_nlinks
);
562 if (input(buf
, 80)) ip
->i_nlinks
= atol(buf
);
563 printf(" size = %6ld", ip
->i_size
);
564 if (input(buf
, 80)) ip
->i_size
= atol(buf
);
565 if (yes("Write this back")) {
566 devwrite(inoaddr(ino
), (char *) ip
, INODE_SIZE
);
569 } while (yes("Do you want to change it again"));
573 /* Allocate `nblk' blocks worth of bitmap. */
574 bitchunk_t
*allocbitmap(nblk
)
577 register bitchunk_t
*bitmap
;
579 bitmap
= (bitchunk_t
*) alloc(nblk
, BLOCK_SIZE
);
584 /* Load the bitmap starting at block `bno' from disk. */
585 void loadbitmap(bitmap
, bno
, nblk
)
591 register bitchunk_t
*p
;
594 for (i
= 0; i
< nblk
; i
++, bno
++, p
+= WORDS_PER_BLOCK
)
595 devread(btoa(bno
), (char *) p
, BLOCK_SIZE
);
599 /* Write the bitmap starting at block `bno' to disk. */
600 void dumpbitmap(bitmap
, bno
, nblk
)
606 register bitchunk_t
*p
= bitmap
;
608 for (i
= 0; i
< nblk
; i
++, bno
++, p
+= WORDS_PER_BLOCK
)
609 devwrite(btoa(bno
), (char *) p
, BLOCK_SIZE
);
612 /* Set the bits given by `list' in the bitmap. */
613 void fillbitmap(bitmap
, lwb
, upb
, list
)
620 if (list
== 0) return;
621 while ((bit
= getnumber(*list
++)) != NO_BIT
)
622 if (bit
< lwb
|| bit
>= upb
) {
623 if (bitmap
== spec_imap
)
624 printf("inode number %u ", bit
);
626 printf("zone number %u ", bit
);
627 printf("out of range (ignored)\n");
629 setbit(bitmap
, bit
- lwb
+ 1);
632 /* Deallocate the bitmap `p'. */
639 /* Get all the bitmaps used by this program. */
642 imap
= allocbitmap(N_IMAP
);
643 zmap
= allocbitmap(N_ZMAP
);
644 spec_imap
= allocbitmap(N_IMAP
);
645 spec_zmap
= allocbitmap(N_ZMAP
);
646 dirmap
= allocbitmap(N_IMAP
);
649 /* Release all the space taken by the bitmaps. */
654 freebitmap(spec_imap
);
655 freebitmap(spec_zmap
);
659 /* `w1' and `w2' are differing words from two bitmaps that should be
660 * identical. Print what's the matter with them.
662 void chkword(w1
, w2
, bit
, type
, n
, report
)
668 for (; (w1
| w2
); w1
>>= 1, w2
>>= 1, bit
++)
669 if ((w1
^ w2
) & 1 && ++(*n
) % MAXPRINT
== 0 && *report
&&
670 (!repair
|| automatic
|| yes("stop this listing")))
673 if ((w1
& 1) && !(w2
& 1))
674 printf("%s %u is missing\n", type
, bit
);
675 else if (!(w1
& 1) && (w2
& 1))
676 printf("%s %u is not free\n", type
, bit
);
679 /* Check if the given (correct) bitmap is identical with the one that is
680 * on the disk. If not, ask if the disk should be repaired.
682 void chkmap(cmap
, dmap
, bit
, blkno
, nblk
, type
)
683 bitchunk_t
*cmap
, *dmap
;
689 register bitchunk_t
*p
= dmap
, *q
= cmap
;
690 int report
= 1, nerr
= 0;
691 int w
= nblk
* WORDS_PER_BLOCK
;
693 printf("Checking %s map\n", type
);
694 loadbitmap(dmap
, blkno
, nblk
);
696 if (*p
!= *q
) chkword(*p
, *q
, bit
, type
, &nerr
, &report
);
699 bit
+= 8 * sizeof(bitchunk_t
);
702 if ((!repair
|| automatic
) && !report
) printf("etc. ");
703 if (nerr
> MAXPRINT
|| nerr
> 10) printf("%d errors found. ", nerr
);
704 if (nerr
!= 0 && yes("install a new map")) dumpbitmap(cmap
, blkno
, nblk
);
705 if (nerr
> 0) printf("\n");
708 /* See if the inodes that aren't allocated are cleared. */
711 register ino_t ino
= 1;
714 printf("Checking inode list\n");
716 if (!bitset(imap
, (bit_nr
) ino
)) {
717 devread(inoaddr(ino
), (char *) &mode
, sizeof(mode
));
718 if (mode
!= I_NOT_ALLOC
) {
719 printf("mode inode %u not cleared", ino
);
720 if (yes(". clear")) devwrite(inoaddr(ino
), nullbuf
,
724 while (++ino
<= sb
.s_ninodes
);
728 /* Allocate an array to maintain the inode reference counts in. */
731 count
= (nlink_t
*) alloc(sb
.s_ninodes
+ 1, sizeof(nlink_t
));
734 /* The reference count for inode `ino' is wrong. Ask if it should be adjusted. */
741 printf("INODE NLINK COUNT\n");
744 devread(inoaddr(ino
), (char *) &inode
, INODE_SIZE
);
745 count
[ino
] += inode
.i_nlinks
;
746 printf("%5u %5u %5u", ino
, (unsigned) inode
.i_nlinks
, count
[ino
]);
747 if (yes(" adjust")) {
748 if ((inode
.i_nlinks
= count
[ino
]) == 0) {
749 fatal("internal error (counterror)");
750 /* This would be a patch
751 inode.i_mode = I_NOT_ALLOC;
752 clrbit(imap, (bit_nr) ino);
755 devwrite(inoaddr(ino
), (char *) &inode
, INODE_SIZE
);
759 /* Check if the reference count of the inodes are correct. The array `count'
760 * is maintained as follows: an entry indexed by the inode number is
761 * incremented each time a link is found; when the inode is read the link
762 * count in there is substracted from the corresponding entry in `count'.
763 * Thus, when the whole file system has been traversed, all the entries
770 for (ino
= 1; ino
<= sb
.s_ninodes
; ino
++)
771 if (count
[ino
] != 0) counterror(ino
);
772 if (!firstcnterr
) printf("\n");
775 /* Deallocate the `count' array. */
778 free((char *) count
);
781 /* Print the inode permission bits given by mode and shift. */
782 void printperm(mode_t mode
, int shift
, int special
, int overlay
)
784 if (mode
>> shift
& R_BIT
)
788 if (mode
>> shift
& W_BIT
)
795 if (mode
>> shift
& X_BIT
)
801 /* List the given inode. */
808 printf(" inode permission link size name\n");
811 switch (ip
->i_mode
& I_TYPE
) {
812 case I_REGULAR
: putchar('-'); break;
813 case I_DIRECTORY
: putchar('d'); break;
814 case I_CHAR_SPECIAL
: putchar('c'); break;
815 case I_BLOCK_SPECIAL
: putchar('b'); break;
816 case I_NAMED_PIPE
: putchar('p'); break;
817 #ifdef I_SYMBOLIC_LINK
818 case I_SYMBOLIC_LINK
: putchar('l'); break;
820 default: putchar('?');
822 printperm(ip
->i_mode
, 6, I_SET_UID_BIT
, 's');
823 printperm(ip
->i_mode
, 3, I_SET_GID_BIT
, 's');
824 printperm(ip
->i_mode
, 0, STICKY_BIT
, 't');
825 printf(" %3u ", ip
->i_nlinks
);
826 switch (ip
->i_mode
& I_TYPE
) {
828 case I_BLOCK_SPECIAL
:
829 printf(" %2x,%2x ", (dev_t
) ip
->i_zone
[0] >> MAJOR
& 0xFF,
830 (dev_t
) ip
->i_zone
[0] >> MINOR
& 0xFF);
832 default: printf("%7ld ", ip
->i_size
);
837 /* Remove an entry from a directory if ok with the user.
838 * Don't name the function remove() - that is owned by ANSI, and chaos results
839 * when it is a macro.
844 setbit(spec_imap
, (bit_nr
) dp
->d_inum
);
845 if (yes(". remove entry")) {
847 memset((void *) dp
, 0, sizeof(dir_struct
));
853 /* Convert string so that embedded control characters are printable. */
854 void make_printable_name(dst
, src
, n
)
861 while (--n
>= 0 && (c
= *src
++) != '\0') {
862 if (isprint(c
) && c
!= '\\')
868 *dst
++ = '\\'; break;
880 *dst
++ = '0' + ((c
>> 6) & 03);
881 *dst
++ = '0' + ((c
>> 3) & 07);
882 *dst
++ = '0' + (c
& 07);
889 /* See if the `.' or `..' entry is as expected. */
890 int chkdots(ino
, pos
, dp
, exp
)
895 char printable_name
[4 * NAME_MAX
+ 1];
897 if (dp
->d_inum
!= exp
) {
898 make_printable_name(printable_name
, dp
->d_name
, sizeof(dp
->d_name
));
899 printf("bad %s in ", printable_name
);
901 printf("%s is linked to %u ", printable_name
, dp
->d_inum
);
902 printf("instead of %u)", exp
);
903 setbit(spec_imap
, (bit_nr
) ino
);
904 setbit(spec_imap
, (bit_nr
) dp
->d_inum
);
905 setbit(spec_imap
, (bit_nr
) exp
);
906 if (yes(". repair")) {
912 } else if (pos
!= (dp
->d_name
[1] ? DIR_ENTRY_SIZE
: 0)) {
913 make_printable_name(printable_name
, dp
->d_name
, sizeof(dp
->d_name
));
914 printf("warning: %s has offset %ld in ", printable_name
, pos
);
916 printf("%s is linked to %u)\n", printable_name
, dp
->d_inum
);
917 setbit(spec_imap
, (bit_nr
) ino
);
918 setbit(spec_imap
, (bit_nr
) dp
->d_inum
);
919 setbit(spec_imap
, (bit_nr
) exp
);
924 /* Check the name in a directory entry. */
929 register n
= NAME_MAX
+ 1;
930 register char *p
= dp
->d_name
;
933 printf("null name found in ");
935 setbit(spec_imap
, (bit_nr
) ino
);
936 if (Remove(dp
)) return(0);
938 while (*p
!= '\0' && --n
!= 0)
940 printf("found a '/' in entry of directory ");
942 setbit(spec_imap
, (bit_nr
) ino
);
944 printname(dp
->d_name
);
946 if (Remove(dp
)) return(0);
952 /* Check a directory entry. Here the routine `descendtree' is called
953 * recursively to check the file or directory pointed to by the entry.
955 int chkentry(ino
, pos
, dp
)
960 if (dp
->d_inum
< ROOT_INODE
|| dp
->d_inum
> sb
.s_ninodes
) {
961 printf("bad inode found in directory ");
963 printf("ino found = %u, ", dp
->d_inum
);
965 printname(dp
->d_name
);
967 if (yes(". remove entry")) {
968 memset((void *) dp
, 0, sizeof(dir_struct
));
973 if ((unsigned) count
[dp
->d_inum
] == CHAR_MAX
) {
974 printf("too many links to ino %u\n", dp
->d_inum
);
975 printf("discovered at entry '");
976 printname(dp
->d_name
);
977 printf("' in directory ");
979 if (Remove(dp
)) return(0);
982 if (strcmp(dp
->d_name
, ".") == 0) {
983 ftop
->st_presence
|= DOT
;
984 return(chkdots(ino
, pos
, dp
, ino
));
986 if (strcmp(dp
->d_name
, "..") == 0) {
987 ftop
->st_presence
|= DOTDOT
;
988 return(chkdots(ino
, pos
, dp
, ino
== ROOT_INODE
? ino
:
989 ftop
->st_next
->st_dir
->d_inum
));
991 if (!chkname(ino
, dp
)) return(0);
992 if (bitset(dirmap
, (bit_nr
) dp
->d_inum
)) {
993 printf("link to directory discovered in ");
996 printname(dp
->d_name
);
997 printf("', dir ino = %u)", dp
->d_inum
);
1000 return(descendtree(dp
));
1003 /* Check a zone of a directory by checking all the entries in the zone.
1004 * The zone is split up into chunks to not allocate too much stack.
1006 int chkdirzone(ino
, ip
, pos
, zno
)
1012 dir_struct dirblk
[CDIRECT
];
1013 register dir_struct
*dp
;
1014 register n
= SCALE
* (NR_DIR_ENTRIES(BLOCK_SIZE
) / CDIRECT
), dirty
;
1015 register long offset
= zaddr(zno
);
1016 register off_t size
= 0;
1019 devread(offset
, (char *) dirblk
, DIRCHUNK
);
1021 for (dp
= dirblk
; dp
< &dirblk
[CDIRECT
]; dp
++) {
1022 if (dp
->d_inum
!= NO_ENTRY
&& !chkentry(ino
, pos
, dp
))
1024 pos
+= DIR_ENTRY_SIZE
;
1025 if (dp
->d_inum
!= NO_ENTRY
) size
= pos
;
1027 if (dirty
) devwrite(offset
, (char *) dirblk
, DIRCHUNK
);
1031 if (size
> ip
->i_size
) {
1032 printf("size not updated of directory ");
1034 if (yes(". extend")) {
1035 setbit(spec_imap
, (bit_nr
) ino
);
1037 devwrite(inoaddr(ino
), (char *) ip
, INODE_SIZE
);
1043 /* There is something wrong with the given zone. Print some details. */
1044 void errzone(mess
, zno
, level
, pos
)
1050 printf("%s zone in ", mess
);
1052 printf("zno = %u, type = ", zno
);
1054 case 0: printf("DATA"); break;
1055 case 1: printf("SINGLE INDIRECT"); break;
1056 case 2: printf("DOUBLE INDIRECT"); break;
1057 default: printf("VERY INDIRECT");
1059 printf(", pos = %ld)\n", pos
);
1062 /* Found the given zone in the given inode. Check it, and if ok, mark it
1063 * in the zone bitmap.
1065 int markzone(ino
, zno
, level
, pos
)
1071 register bit_nr bit
= (bit_nr
) zno
- FIRST
+ 1;
1074 if (zno
< FIRST
|| zno
>= sb
.s_nzones
) {
1075 errzone("out-of-range", zno
, level
, pos
);
1078 if (bitset(zmap
, bit
)) {
1079 setbit(spec_zmap
, bit
);
1080 errzone("duplicate", zno
, level
, pos
);
1084 if (bitset(spec_zmap
, bit
)) errzone("found", zno
, level
, pos
);
1089 /* Check an indirect zone by checking all of its entries.
1090 * The zone is split up into chunks to not allocate too much stack.
1092 int chkindzone(ino
, ip
, pos
, zno
, level
)
1099 zone_nr indirect
[CINDIR
];
1100 register n
= NR_INDIRECTS
/ CINDIR
;
1101 register long offset
= zaddr(zno
);
1104 devread(offset
, (char *) indirect
, INDCHUNK
);
1105 if (!chkzones(ino
, ip
, pos
, indirect
, CINDIR
, level
- 1)) return(0);
1107 } while (--n
&& *pos
< ip
->i_size
);
1111 /* Return the size of a gap in the file, represented by a null zone number
1112 * at some level of indirection.
1117 off_t power
= ZONE_SIZE
;
1120 power
*= NR_INDIRECTS
;
1125 /* Check a zone, which may be either a normal data zone, a directory zone,
1126 * or an indirect zone.
1128 int zonechk(ino
, ip
, pos
, zno
, level
)
1136 if ((ip
->i_mode
& I_TYPE
) == I_DIRECTORY
&&
1137 !chkdirzone(ino
, ip
, *pos
, zno
))
1142 return chkindzone(ino
, ip
, pos
, zno
, level
);
1145 /* Check a list of zones given by `zlist'. */
1146 int chkzones(ino
, ip
, pos
, zlist
, len
, level
)
1156 /* The check on the position in the next loop is commented out, since FS
1157 * now requires valid zone numbers in each level that is necessary and FS
1158 * always deleted all the zones in the double indirect block.
1160 for (i
= 0; i
< len
/* && *pos < ip->i_size */ ; i
++)
1161 if (zlist
[i
] == NO_ZONE
)
1162 *pos
+= jump(level
);
1163 else if (!markzone(ino
, zlist
[i
], level
, *pos
)) {
1164 *pos
+= jump(level
);
1166 } else if (!zonechk(ino
, ip
, pos
, zlist
[i
], level
))
1171 /* Check a file or a directory. */
1172 int chkfile(ino
, ip
)
1176 register ok
, i
, level
;
1179 ok
= chkzones(ino
, ip
, &pos
, (zone_nr
*)&ip
->i_zone
[0], NR_DZONE_NUM
, 0);
1180 for (i
= NR_DZONE_NUM
, level
= 1; i
< NR_ZONE_NUMS
; i
++, level
++)
1181 ok
&= chkzones(ino
, ip
, &pos
, (zone_nr
*)&ip
->i_zone
[i
], 1, level
);
1185 /* Check a directory by checking the contents. Check if . and .. are present. */
1186 int chkdirectory(ino
, ip
)
1192 setbit(dirmap
, (bit_nr
) ino
);
1193 ok
= chkfile(ino
, ip
);
1194 if (!(ftop
->st_presence
& DOT
)) {
1195 printf(". missing in ");
1199 if (!(ftop
->st_presence
& DOTDOT
)) {
1200 printf(".. missing in ");
1207 #ifdef I_SYMBOLIC_LINK
1209 /* Check the validity of a symbolic link. */
1210 int chklink(ino
, ip
)
1216 ok
= chkfile(ino
, ip
);
1217 if (ip
->i_size
<= 0 || ip
->i_size
> BLOCK_SIZE
) {
1218 if (ip
->i_size
== 0)
1219 printf("empty symbolic link ");
1221 printf("symbolic link too large (size %ld) ", ip
->i_size
);
1230 /* Check the validity of a special file. */
1231 int chkspecial(ino
, ip
)
1238 if ((dev_t
) ip
->i_zone
[0] == NO_DEV
) {
1239 printf("illegal device number %u for special file ", ip
->i_zone
[0]);
1244 /* FS will not use the remaining "zone numbers" but 1.6.11++ will panic if
1245 * they are nonzero, since this should not happen.
1247 for (i
= 1; i
< NR_ZONE_NUMS
; i
++)
1248 if (ip
->i_zone
[i
] != NO_ZONE
) {
1249 printf("nonzero zone number %u for special file ",
1257 /* Check the mode and contents of an inode. */
1258 int chkmode(ino
, ip
)
1262 switch (ip
->i_mode
& I_TYPE
) {
1265 return chkfile(ino
, ip
);
1268 return chkdirectory(ino
, ip
);
1269 case I_BLOCK_SPECIAL
:
1271 return chkspecial(ino
, ip
);
1272 case I_CHAR_SPECIAL
:
1274 return chkspecial(ino
, ip
);
1277 return chkfile(ino
, ip
);
1278 #ifdef I_SYMBOLIC_LINK
1279 case I_SYMBOLIC_LINK
:
1281 return chklink(ino
, ip
);
1285 printf("bad mode of ");
1287 printf("mode = %o)", ip
->i_mode
);
1292 /* Check an inode. */
1293 int chkinode(ino
, ip
)
1297 if (ino
== ROOT_INODE
&& (ip
->i_mode
& I_TYPE
) != I_DIRECTORY
) {
1298 printf("root inode is not a directory ");
1299 printf("(ino = %u, mode = %o)\n", ino
, ip
->i_mode
);
1302 if (ip
->i_nlinks
== 0) {
1303 printf("link count zero of ");
1308 setbit(imap
, (bit_nr
) ino
);
1309 if ((unsigned) ip
->i_nlinks
> CHAR_MAX
) {
1310 printf("link count too big in ");
1312 printf("cnt = %u)\n", (unsigned) ip
->i_nlinks
);
1313 count
[ino
] -= CHAR_MAX
;
1314 setbit(spec_imap
, (bit_nr
) ino
);
1316 count
[ino
] -= (unsigned) ip
->i_nlinks
;
1317 return chkmode(ino
, ip
);
1320 /* Check the directory entry pointed to by dp, by checking the inode. */
1325 register ino_t ino
= dp
->d_inum
;
1332 if (bitset(spec_imap
, (bit_nr
) ino
)) {
1333 printf("found inode %u: ", ino
);
1336 visited
= bitset(imap
, (bit_nr
) ino
);
1337 if (!visited
|| listing
) {
1338 devread(inoaddr(ino
), (char *) &inode
, INODE_SIZE
);
1339 if (listing
) list(ino
, &inode
);
1340 if (!visited
&& !chkinode(ino
, &inode
)) {
1341 setbit(spec_imap
, (bit_nr
) ino
);
1342 if (yes("remove")) {
1343 count
[ino
] += inode
.i_nlinks
- 1;
1344 clrbit(imap
, (bit_nr
) ino
);
1345 devwrite(inoaddr(ino
), nullbuf
, INODE_SIZE
);
1346 memset((void *) dp
, 0, sizeof(dir_struct
));
1347 ftop
= ftop
->st_next
;
1352 ftop
= ftop
->st_next
;
1356 /* Check the file system tree. */
1361 nfreeinode
= sb
.s_ninodes
;
1363 dir
.d_inum
= ROOT_INODE
;
1365 if (!descendtree(&dir
)) fatal("bad root inode");
1369 /* Print the totals of all the objects found. */
1372 printf("blocksize = %5d ", BLOCK_SIZE
);
1373 printf("zonesize = %5d\n", ZONE_SIZE
);
1375 pr("%6u Regular file%s\n", nregular
, "", "s");
1376 pr("%6u Director%s\n", ndirectory
, "y", "ies");
1377 pr("%6u Block special file%s\n", nblkspec
, "", "s");
1378 pr("%6u Character special file%s\n", ncharspec
, "", "s");
1379 if (nbadinode
!= 0) pr("%6u Bad inode%s\n", nbadinode
, "", "s");
1380 pr("%6u Free inode%s\n", nfreeinode
, "", "s");
1381 pr("%6u Named pipe%s\n", npipe
, "", "s");
1382 pr("%6u Symbolic link%s\n", nsyml
, "", "s");
1383 /* Don't print some fields.
1385 pr("%6u Data zone%s\n", ztype[0], "", "s");
1386 pr("%6u Single indirect zone%s\n", ztype[1], "", "s");
1387 pr("%6u Double indirect zone%s\n", ztype[2], "", "s");
1389 pr("%6u Free zone%s\n", nfreezone
, "", "s");
1392 /* Check the device which name is given by `f'. The inodes listed by `clist'
1393 * should be listed separately, and the inodes listed by `ilist' and the zones
1394 * listed by `zlist' should be watched for while checking the file system.
1397 void chkdev(f
, clist
, ilist
, zlist
)
1398 char *f
, **clist
, **ilist
, **zlist
;
1400 if (automatic
) repair
= 1;
1413 fillbitmap(spec_imap
, (bit_nr
) 1, (bit_nr
) sb
.s_ninodes
+ 1, ilist
);
1414 fillbitmap(spec_zmap
, (bit_nr
) FIRST
, (bit_nr
) sb
.s_nzones
, zlist
);
1418 chkmap(zmap
, spec_zmap
, (bit_nr
) FIRST
- 1, BLK_ZMAP
, N_ZMAP
, "zone");
1420 chkmap(imap
, spec_imap
, (bit_nr
) 0, BLK_IMAP
, N_IMAP
, "inode");
1428 if (changed
) printf("----- FILE SYSTEM HAS BEEN MODIFIED -----\n\n");
1431 int main(argc
, argv
)
1435 register char **clist
= 0, **ilist
= 0, **zlist
= 0;
1437 register devgiven
= 0;
1440 if ((1 << BITSHIFT
) != 8 * sizeof(bitchunk_t
)) {
1441 printf("Fsck was compiled with the wrong BITSHIFT!\n");
1447 while ((arg
= *argv
++) != 0)
1448 if (arg
[0] == '-' && arg
[1] != 0 && arg
[2] == 0) switch (arg
[1]) {
1449 case 'a': automatic
^= 1; break;
1451 clist
= getlist(&argv
, "inode");
1454 ilist
= getlist(&argv
, "inode");
1457 zlist
= getlist(&argv
, "zone");
1459 case 'r': repair
^= 1; break;
1460 case 'l': listing
^= 1; break;
1461 case 's': listsuper
^= 1; break;
1463 printf("%s: unknown flag '%s'\n", prog
, arg
);
1466 chkdev(arg
, clist
, ilist
, zlist
);
1473 printf("Usage: fsck1 [-acilrsz] file\n");