]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - disk-utils/fsck.minix.c
2 * fsck.c - a file system consistency checker for Linux.
4 * (C) 1991, 1992 Linus Torvalds. This file may be redistributed
5 * as per the GNU copyleft.
9 * 09.11.91 - made the first rudimetary functions
11 * 10.11.91 - updated, does checking, no repairs yet.
12 * Sent out to the mailing-list for testing.
14 * 14.11.91 - Testing seems to have gone well. Added some
15 * correction-code, and changed some functions.
17 * 15.11.91 - More correction code. Hopefully it notices most
18 * cases now, and tries to do something about them.
20 * 16.11.91 - More corrections (thanks to Mika Jalava). Most
21 * things seem to work now. Yeah, sure.
24 * 19.04.92 - Had to start over again from this old version, as a
25 * kernel bug ate my enhanced fsck in february.
27 * 28.02.93 - added support for different directory entry sizes..
29 * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with
30 * super-block information
32 * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform
33 * to that required by fsutil
35 * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu)
36 * Added support for file system valid flag. Also
37 * added program_version variable and output of
38 * program name and version number when program
41 * 30.10.94 - added support for v2 filesystem
42 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
44 * 10.12.94 - added test to prevent checking of mounted fs adapted
45 * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck
46 * program. (Daniel Quinlan, quinlan@yggdrasil.com)
48 * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such
49 * for modern libcs (janl@math.uio.no, Nicolai Langfeldt)
51 * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk
52 * (Russell King). He made them for ARM. It would seem
53 * that the ARM is powerful enough to do this in C whereas
54 * i386 and m64k must use assembly to get it fast >:-)
55 * This should make minix fsck systemindependent.
56 * (janl@math.uio.no, Nicolai Langfeldt)
58 * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler
59 * warnings. Added mc68k bitops from
60 * Joerg Dorchain <dorchain@mpi-sb.mpg.de>.
62 * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by
65 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
66 * - added Native Language Support
69 * I've had no time to add comments - hopefully the function names
70 * are comments enough. As with all file system checkers, this assumes
71 * the file system is quiescent - don't use it on a mounted device
72 * unless you can be sure nobody is writing to it (and remember that the
73 * kernel can write to it when it searches for files).
75 * Usuage: fsck [-larvsm] device
76 * -l for a listing of all the filenames
77 * -a for automatic repairs (not implemented)
78 * -r for repairs (interactive) (not implemented)
79 * -v for verbose (tells how many files)
80 * -s for super-block info
81 * -m for minix-like "mode not cleared" warnings
82 * -f force filesystem check even if filesystem marked as valid
84 * The device may be a block device or a image of one, but this isn't
85 * enforced (but it's not much fun on a character device :-).
102 #ifdef MINIX2_SUPER_MAGIC2
103 #define HAVE_MINIX2 1
112 #define UPPER(size,n) ((size+((n)-1))/(n))
113 #define INODE_SIZE (sizeof(struct minix_inode))
115 #define INODE_SIZE2 (sizeof(struct minix2_inode))
116 #define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
117 : MINIX_INODES_PER_BLOCK))
119 #define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
121 #define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
123 #define BITS_PER_BLOCK (BLOCK_SIZE<<3)
125 static char * program_name
= "fsck.minix";
126 static char * device_name
= NULL
;
128 static int repair
=0, automatic
=0, verbose
=0, list
=0, show
=0, warn_mode
=0,
130 static int directory
=0, regular
=0, blockdev
=0, chardev
=0, links
=0,
133 static int changed
= 0; /* flags if the filesystem has been changed */
134 static int errors_uncorrected
= 0; /* flag if some error was not corrected */
135 static int dirsize
= 16;
136 static int namelen
= 14;
137 static int version2
= 0;
138 static struct termios termios
;
139 static int termios_set
= 0;
143 static int name_depth
= 0;
144 static char name_list
[MAX_DEPTH
][NAME_MAX
+1];
146 static char * inode_buffer
= NULL
;
147 #define Inode (((struct minix_inode *) inode_buffer)-1)
148 #define Inode2 (((struct minix2_inode *) inode_buffer)-1)
149 static char super_block_buffer
[BLOCK_SIZE
];
150 #define Super (*(struct minix_super_block *)super_block_buffer)
151 #define INODES ((unsigned long)Super.s_ninodes)
153 #define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
155 #define ZONES ((unsigned long)(Super.s_nzones))
157 #define IMAPS ((unsigned long)Super.s_imap_blocks)
158 #define ZMAPS ((unsigned long)Super.s_zmap_blocks)
159 #define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
160 #define ZONESIZE ((unsigned long)Super.s_log_zone_size)
161 #define MAXSIZE ((unsigned long)Super.s_max_size)
162 #define MAGIC (Super.s_magic)
163 #define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
165 static char *inode_map
;
166 static char *zone_map
;
168 static unsigned char * inode_count
= NULL
;
169 static unsigned char * zone_count
= NULL
;
171 static void recursive_check(unsigned int ino
);
173 static void recursive_check2(unsigned int ino
);
178 #define inode_in_use(x) (bit(inode_map,(x)))
179 #define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
181 #define mark_inode(x) (setbit(inode_map,(x)),changed=1)
182 #define unmark_inode(x) (clrbit(inode_map,(x)),changed=1)
184 #define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1)
185 #define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1)
190 tcsetattr(0, TCSANOW
, &termios
);
197 _("Usage: %s [-larvsmf] /dev/name\n"),
203 die(const char *str
) {
204 fprintf(stderr
, "%s: %s\n", program_name
, str
);
209 * This simply goes through the file-name data and prints out the
213 print_current_name(void) {
216 while (i
< name_depth
)
217 printf("/%.*s", namelen
, name_list
[i
++]);
223 ask(const char * string
, int def
) {
228 errors_uncorrected
= 1;
234 errors_uncorrected
= 1;
237 printf(def
?"%s (y/n)? ":"%s (n/y)? ",string
);
240 if ((c
=getchar())==EOF
) {
242 errors_uncorrected
= 1;
249 } else if (c
== 'N') {
252 } else if (c
== ' ' || c
== '\n')
259 errors_uncorrected
= 1;
265 * Make certain that we aren't checking a filesystem that is on a
266 * mounted partition. Code adapted from e2fsck, Copyright (C) 1993,
267 * 1994 Theodore Ts'o. Also licensed under GPL.
276 if ((f
= setmntent (MOUNTED
, "r")) == NULL
)
278 while ((mnt
= getmntent (f
)) != NULL
)
279 if (strcmp (device_name
, mnt
->mnt_fsname
) == 0)
286 * If the root is mounted read-only, then /etc/mtab is
287 * probably not correct; so we won't issue a warning based on
290 fd
= open(MOUNTED
, O_RDWR
);
291 if (fd
< 0 && errno
== EROFS
)
296 printf (_("%s is mounted. "), device_name
);
297 if (isatty(0) && isatty(1))
298 cont
= ask(_("Do you really want to continue"), 0);
302 printf (_("check aborted.\n"));
309 * check_zone_nr checks to see that *nr is a valid zone nr. If it
310 * isn't, it will possibly be repaired. Check_zone_nr sets *corrected
311 * if an error was corrected, and returns the zone (0 for no zone
312 * or a bad zone-number).
315 check_zone_nr(unsigned short * nr
, int * corrected
) {
319 printf(_("Zone nr < FIRSTZONE in file `"));
320 else if (*nr
>= ZONES
)
321 printf(_("Zone nr >= ZONES in file `"));
324 print_current_name();
326 if (ask(_("Remove block"),1)) {
335 check_zone_nr2 (unsigned int *nr
, int *corrected
) {
339 printf (_("Zone nr < FIRSTZONE in file `"));
340 else if (*nr
>= ZONES
)
341 printf (_("Zone nr >= ZONES in file `"));
344 print_current_name ();
346 if (ask (_("Remove block"), 1)) {
355 * read-block reads block nr into the buffer at addr.
358 read_block(unsigned int nr
, char * addr
) {
360 memset(addr
,0,BLOCK_SIZE
);
363 if (BLOCK_SIZE
*nr
!= lseek(IN
, BLOCK_SIZE
*nr
, SEEK_SET
)) {
364 printf(_("Read error: unable to seek to block in file '"));
365 print_current_name();
367 memset(addr
,0,BLOCK_SIZE
);
368 errors_uncorrected
= 1;
369 } else if (BLOCK_SIZE
!= read(IN
, addr
, BLOCK_SIZE
)) {
370 printf(_("Read error: bad block in file '"));
371 print_current_name();
373 memset(addr
,0,BLOCK_SIZE
);
374 errors_uncorrected
= 1;
379 * write_block writes block nr to disk.
382 write_block(unsigned int nr
, char * addr
) {
385 if (nr
< FIRSTZONE
|| nr
>= ZONES
) {
386 printf(_("Internal error: trying to write bad block\n"
387 "Write request ignored\n"));
388 errors_uncorrected
= 1;
391 if (BLOCK_SIZE
*nr
!= lseek(IN
, BLOCK_SIZE
*nr
, SEEK_SET
))
392 die(_("seek failed in write_block"));
393 if (BLOCK_SIZE
!= write(IN
, addr
, BLOCK_SIZE
)) {
394 printf(_("Write error: bad block in file '"));
395 print_current_name();
397 errors_uncorrected
= 1;
402 * map-block calculates the absolute block nr of a block in a file.
403 * It sets 'changed' if the inode has needed changing, and re-writes
404 * any indirect blocks with errors.
407 map_block(struct minix_inode
* inode
, unsigned int blknr
) {
408 unsigned short ind
[BLOCK_SIZE
>>1];
409 unsigned short dind
[BLOCK_SIZE
>>1];
410 int blk_chg
, block
, result
;
413 return check_zone_nr(inode
->i_zone
+ blknr
, &changed
);
416 block
= check_zone_nr(inode
->i_zone
+ 7, &changed
);
417 read_block(block
, (char *) ind
);
419 result
= check_zone_nr(blknr
+ ind
, &blk_chg
);
421 write_block(block
, (char *) ind
);
425 block
= check_zone_nr(inode
->i_zone
+ 8, &changed
);
426 read_block(block
, (char *) dind
);
428 result
= check_zone_nr(dind
+ (blknr
/512), &blk_chg
);
430 write_block(block
, (char *) dind
);
432 read_block(block
, (char *) ind
);
434 result
= check_zone_nr(ind
+ (blknr
%512), &blk_chg
);
436 write_block(block
, (char *) ind
);
442 map_block2 (struct minix2_inode
*inode
, unsigned int blknr
) {
443 unsigned int ind
[BLOCK_SIZE
>> 2];
444 unsigned int dind
[BLOCK_SIZE
>> 2];
445 unsigned int tind
[BLOCK_SIZE
>> 2];
446 int blk_chg
, block
, result
;
449 return check_zone_nr2 (inode
->i_zone
+ blknr
, &changed
);
452 block
= check_zone_nr2 (inode
->i_zone
+ 7, &changed
);
453 read_block (block
, (char *) ind
);
455 result
= check_zone_nr2 (blknr
+ ind
, &blk_chg
);
457 write_block (block
, (char *) ind
);
461 if (blknr
>= 256 * 256) {
462 block
= check_zone_nr2 (inode
->i_zone
+ 8, &changed
);
463 read_block (block
, (char *) dind
);
465 result
= check_zone_nr2 (dind
+ blknr
/ 256, &blk_chg
);
467 write_block (block
, (char *) dind
);
469 read_block (block
, (char *) ind
);
471 result
= check_zone_nr2 (ind
+ blknr
% 256, &blk_chg
);
473 write_block (block
, (char *) ind
);
477 block
= check_zone_nr2 (inode
->i_zone
+ 9, &changed
);
478 read_block (block
, (char *) tind
);
480 result
= check_zone_nr2 (tind
+ blknr
/ (256 * 256), &blk_chg
);
482 write_block (block
, (char *) tind
);
484 read_block (block
, (char *) dind
);
486 result
= check_zone_nr2 (dind
+ (blknr
/ 256) % 256, &blk_chg
);
488 write_block (block
, (char *) dind
);
490 read_block (block
, (char *) ind
);
492 result
= check_zone_nr2 (ind
+ blknr
% 256, &blk_chg
);
494 write_block (block
, (char *) ind
);
500 write_super_block(void) {
502 * Set the state of the filesystem based on whether or not there
503 * are uncorrected errors. The filesystem valid flag is
504 * unconditionally set if we get this far.
506 Super
.s_state
|= MINIX_VALID_FS
;
507 if ( errors_uncorrected
)
508 Super
.s_state
|= MINIX_ERROR_FS
;
510 Super
.s_state
&= ~MINIX_ERROR_FS
;
512 if (BLOCK_SIZE
!= lseek(IN
, BLOCK_SIZE
, SEEK_SET
))
513 die(_("seek failed in write_super_block"));
514 if (BLOCK_SIZE
!= write(IN
, super_block_buffer
, BLOCK_SIZE
))
515 die(_("unable to write super-block"));
524 if (IMAPS
*BLOCK_SIZE
!= write(IN
,inode_map
,IMAPS
*BLOCK_SIZE
))
525 die(_("Unable to write inode map"));
526 if (ZMAPS
*BLOCK_SIZE
!= write(IN
,zone_map
,ZMAPS
*BLOCK_SIZE
))
527 die(_("Unable to write zone map"));
528 if (INODE_BUFFER_SIZE
!= write(IN
,inode_buffer
,INODE_BUFFER_SIZE
))
529 die(_("Unable to write inodes"));
535 char blk
[BLOCK_SIZE
];
540 block
= Inode2
[ROOT_INO
].i_zone
[0];
543 block
= Inode
[ROOT_INO
].i_zone
[0];
544 read_block (block
, blk
);
545 for (size
= 16; size
< BLOCK_SIZE
; size
<<= 1) {
546 if (strcmp (blk
+ size
+ 2, "..") == 0) {
556 read_superblock(void) {
557 if (BLOCK_SIZE
!= lseek(IN
, BLOCK_SIZE
, SEEK_SET
))
558 die(_("seek failed"));
559 if (BLOCK_SIZE
!= read(IN
, super_block_buffer
, BLOCK_SIZE
))
560 die(_("unable to read super block"));
561 if (MAGIC
== MINIX_SUPER_MAGIC
) {
565 } else if (MAGIC
== MINIX_SUPER_MAGIC2
) {
570 } else if (MAGIC
== MINIX2_SUPER_MAGIC
) {
574 } else if (MAGIC
== MINIX2_SUPER_MAGIC2
) {
580 die(_("bad magic number in super-block"));
581 if (ZONESIZE
!= 0 || BLOCK_SIZE
!= 1024)
582 die(_("Only 1k blocks/zones supported"));
583 if (IMAPS
* BLOCK_SIZE
* 8 < INODES
+ 1)
584 die(_("bad s_imap_blocks field in super-block"));
585 if (ZMAPS
* BLOCK_SIZE
* 8 < ZONES
- FIRSTZONE
+ 1)
586 die(_("bad s_zmap_blocks field in super-block"));
591 inode_map
= malloc(IMAPS
* BLOCK_SIZE
);
593 die(_("Unable to allocate buffer for inode map"));
594 zone_map
= malloc(ZMAPS
* BLOCK_SIZE
);
596 die("Unable to allocate buffer for zone map");
597 memset(inode_map
,0,sizeof(inode_map
));
598 memset(zone_map
,0,sizeof(zone_map
));
599 inode_buffer
= malloc(INODE_BUFFER_SIZE
);
601 die(_("Unable to allocate buffer for inodes"));
602 inode_count
= malloc(INODES
+ 1);
604 die(_("Unable to allocate buffer for inode count"));
605 zone_count
= malloc(ZONES
);
607 die(_("Unable to allocate buffer for zone count"));
608 if (IMAPS
*BLOCK_SIZE
!= read(IN
,inode_map
,IMAPS
*BLOCK_SIZE
))
609 die(_("Unable to read inode map"));
610 if (ZMAPS
*BLOCK_SIZE
!= read(IN
,zone_map
,ZMAPS
*BLOCK_SIZE
))
611 die(_("Unable to read zone map"));
612 if (INODE_BUFFER_SIZE
!= read(IN
,inode_buffer
,INODE_BUFFER_SIZE
))
613 die(_("Unable to read inodes"));
614 if (NORM_FIRSTZONE
!= FIRSTZONE
) {
615 printf(_("Warning: Firstzone != Norm_firstzone\n"));
616 errors_uncorrected
= 1;
620 printf(_("%ld inodes\n"),INODES
);
621 printf(_("%ld blocks\n"),ZONES
);
622 printf(_("Firstdatazone=%ld (%ld)\n"),FIRSTZONE
,NORM_FIRSTZONE
);
623 printf(_("Zonesize=%d\n"),BLOCK_SIZE
<<ZONESIZE
);
624 printf(_("Maxsize=%ld\n"),MAXSIZE
);
625 printf(_("Filesystem state=%d\n"), Super
.s_state
);
626 printf(_("namelen=%d\n\n"),namelen
);
630 static struct minix_inode
*
631 get_inode(unsigned int nr
) {
632 struct minix_inode
* inode
;
634 if (!nr
|| nr
> INODES
)
638 if (!inode_count
[nr
]) {
639 if (!inode_in_use(nr
)) {
640 printf(_("Inode %d marked not used, but used for file '"),
642 print_current_name();
645 if (ask(_("Mark in use"),1))
648 errors_uncorrected
= 1;
651 if (S_ISDIR(inode
->i_mode
))
653 else if (S_ISREG(inode
->i_mode
))
655 else if (S_ISCHR(inode
->i_mode
))
657 else if (S_ISBLK(inode
->i_mode
))
659 else if (S_ISLNK(inode
->i_mode
))
661 else if (S_ISSOCK(inode
->i_mode
))
663 else if (S_ISFIFO(inode
->i_mode
))
666 print_current_name();
667 printf(_(" has mode %05o\n"),inode
->i_mode
);
672 if (!++inode_count
[nr
]) {
673 printf(_("Warning: inode count too big.\n"));
675 errors_uncorrected
= 1;
681 static struct minix2_inode
*
682 get_inode2 (unsigned int nr
) {
683 struct minix2_inode
*inode
;
685 if (!nr
|| nr
> INODES
)
689 if (!inode_count
[nr
]) {
690 if (!inode_in_use (nr
)) {
691 printf (_("Inode %d marked not used, but used for file '"), nr
);
692 print_current_name ();
695 if (ask (_("Mark in use"), 1))
698 errors_uncorrected
= 1;
701 if (S_ISDIR (inode
->i_mode
))
703 else if (S_ISREG (inode
->i_mode
))
705 else if (S_ISCHR (inode
->i_mode
))
707 else if (S_ISBLK (inode
->i_mode
))
709 else if (S_ISLNK (inode
->i_mode
))
711 else if (S_ISSOCK (inode
->i_mode
));
712 else if (S_ISFIFO (inode
->i_mode
));
714 print_current_name ();
715 printf (_(" has mode %05o\n"), inode
->i_mode
);
719 if (!++inode_count
[nr
]) {
720 printf (_("Warning: inode count too big.\n"));
722 errors_uncorrected
= 1;
730 struct minix_inode
* inode
= Inode
+ ROOT_INO
;
732 if (!inode
|| !S_ISDIR(inode
->i_mode
))
733 die(_("root inode isn't a directory"));
739 struct minix2_inode
*inode
= Inode2
+ ROOT_INO
;
741 if (!inode
|| !S_ISDIR (inode
->i_mode
))
742 die ("root inode isn't a directory");
747 add_zone(unsigned short * znr
, int * corrected
) {
752 block
= check_zone_nr(znr
, corrected
);
755 if (zone_count
[block
]) {
756 printf(_("Block has been used before. Now in file `"));
757 print_current_name();
759 if (ask(_("Clear"),1)) {
767 if (!zone_in_use(block
)) {
768 printf(_("Block %d in file `"),block
);
769 print_current_name();
770 printf(_("' is marked not in use."));
771 if (ask(_("Correct"),1))
774 if (!++zone_count
[block
])
781 add_zone2 (unsigned int *znr
, int *corrected
) {
786 block
= check_zone_nr2 (znr
, corrected
);
789 if (zone_count
[block
]) {
790 printf (_("Block has been used before. Now in file `"));
791 print_current_name ();
793 if (ask (_("Clear"), 1)) {
801 if (!zone_in_use (block
)) {
802 printf (_("Block %d in file `"), block
);
803 print_current_name ();
804 printf (_("' is marked not in use."));
805 if (ask (_("Correct"), 1))
808 if (!++zone_count
[block
])
815 add_zone_ind(unsigned short * znr
, int * corrected
) {
816 static char blk
[BLOCK_SIZE
];
820 block
= add_zone(znr
, corrected
);
823 read_block(block
, blk
);
824 for (i
=0 ; i
< (BLOCK_SIZE
>>1) ; i
++)
825 add_zone(i
+ (unsigned short *) blk
, &chg_blk
);
827 write_block(block
, blk
);
832 add_zone_ind2 (unsigned int *znr
, int *corrected
) {
833 static char blk
[BLOCK_SIZE
];
837 block
= add_zone2 (znr
, corrected
);
840 read_block (block
, blk
);
841 for (i
= 0; i
< BLOCK_SIZE
>> 2; i
++)
842 add_zone2 (i
+ (unsigned int *) blk
, &chg_blk
);
844 write_block (block
, blk
);
849 add_zone_dind(unsigned short * znr
, int * corrected
) {
850 static char blk
[BLOCK_SIZE
];
854 block
= add_zone(znr
, corrected
);
857 read_block(block
, blk
);
858 for (i
=0 ; i
< (BLOCK_SIZE
>>1) ; i
++)
859 add_zone_ind(i
+ (unsigned short *) blk
, &blk_chg
);
861 write_block(block
, blk
);
866 add_zone_dind2 (unsigned int *znr
, int *corrected
) {
867 static char blk
[BLOCK_SIZE
];
871 block
= add_zone2 (znr
, corrected
);
874 read_block (block
, blk
);
875 for (i
= 0; i
< BLOCK_SIZE
>> 2; i
++)
876 add_zone_ind2 (i
+ (unsigned int *) blk
, &blk_chg
);
878 write_block (block
, blk
);
882 add_zone_tind2 (unsigned int *znr
, int *corrected
) {
883 static char blk
[BLOCK_SIZE
];
887 block
= add_zone2 (znr
, corrected
);
890 read_block (block
, blk
);
891 for (i
= 0; i
< BLOCK_SIZE
>> 2; i
++)
892 add_zone_dind2 (i
+ (unsigned int *) blk
, &blk_chg
);
894 write_block (block
, blk
);
899 check_zones(unsigned int i
) {
900 struct minix_inode
* inode
;
902 if (!i
|| i
> INODES
)
904 if (inode_count
[i
] > 1) /* have we counted this file already? */
907 if (!S_ISDIR(inode
->i_mode
) && !S_ISREG(inode
->i_mode
) &&
908 !S_ISLNK(inode
->i_mode
))
910 for (i
=0 ; i
<7 ; i
++)
911 add_zone(i
+ inode
->i_zone
, &changed
);
912 add_zone_ind(7 + inode
->i_zone
, &changed
);
913 add_zone_dind(8 + inode
->i_zone
, &changed
);
918 check_zones2 (unsigned int i
) {
919 struct minix2_inode
*inode
;
921 if (!i
|| i
> INODES
)
923 if (inode_count
[i
] > 1) /* have we counted this file already? */
926 if (!S_ISDIR (inode
->i_mode
) && !S_ISREG (inode
->i_mode
)
927 && !S_ISLNK (inode
->i_mode
))
929 for (i
= 0; i
< 7; i
++)
930 add_zone2 (i
+ inode
->i_zone
, &changed
);
931 add_zone_ind2 (7 + inode
->i_zone
, &changed
);
932 add_zone_dind2 (8 + inode
->i_zone
, &changed
);
933 add_zone_tind2 (9 + inode
->i_zone
, &changed
);
938 check_file(struct minix_inode
* dir
, unsigned int offset
) {
939 static char blk
[BLOCK_SIZE
];
940 struct minix_inode
* inode
;
945 block
= map_block(dir
,offset
/BLOCK_SIZE
);
946 read_block(block
, blk
);
947 name
= blk
+ (offset
% BLOCK_SIZE
) + 2;
948 ino
= * (unsigned short *) (name
-2);
950 print_current_name();
951 printf(_(" contains a bad inode number for file '"));
952 printf("%.*s'.",namelen
,name
);
953 if (ask(_(" Remove"),1)) {
954 *(unsigned short *)(name
-2) = 0;
955 write_block(block
, blk
);
959 if (name_depth
< MAX_DEPTH
)
960 strncpy (name_list
[name_depth
], name
, namelen
);
962 inode
= get_inode(ino
);
965 if (!inode
|| strcmp(".",name
)) {
966 print_current_name();
967 printf(_(": bad directory: '.' isn't first\n"));
968 errors_uncorrected
= 1;
971 if (offset
== dirsize
) {
972 if (!inode
|| strcmp("..",name
)) {
973 print_current_name();
974 printf(_(": bad directory: '..' isn't second\n"));
975 errors_uncorrected
= 1;
980 if (name_depth
< MAX_DEPTH
)
981 strncpy(name_list
[name_depth
], name
, namelen
);
985 printf("%6d %07o %3d ",ino
,inode
->i_mode
,inode
->i_nlinks
);
986 print_current_name();
987 if (S_ISDIR(inode
->i_mode
))
993 if (inode
&& S_ISDIR(inode
->i_mode
))
994 recursive_check(ino
);
1001 check_file2 (struct minix2_inode
*dir
, unsigned int offset
) {
1002 static char blk
[BLOCK_SIZE
];
1003 struct minix2_inode
*inode
;
1008 block
= map_block2 (dir
, offset
/ BLOCK_SIZE
);
1009 read_block (block
, blk
);
1010 name
= blk
+ (offset
% BLOCK_SIZE
) + 2;
1011 ino
= *(unsigned short *) (name
- 2);
1013 print_current_name ();
1014 printf (_(" contains a bad inode number for file '"));
1015 printf ("%.*s'.", namelen
, name
);
1016 if (ask (_(" Remove"), 1)) {
1017 *(unsigned short *) (name
- 2) = 0;
1018 write_block (block
, blk
);
1022 if (name_depth
< MAX_DEPTH
)
1023 strncpy (name_list
[name_depth
], name
, namelen
);
1025 inode
= get_inode2 (ino
);
1028 if (!inode
|| strcmp (".", name
)) {
1029 print_current_name ();
1030 printf (_(": bad directory: '.' isn't first\n"));
1031 errors_uncorrected
= 1;
1035 if (offset
== dirsize
) {
1036 if (!inode
|| strcmp ("..", name
)) {
1037 print_current_name ();
1038 printf (_(": bad directory: '..' isn't second\n"));
1039 errors_uncorrected
= 1;
1048 printf ("%6d %07o %3d ", ino
, inode
->i_mode
, inode
->i_nlinks
);
1049 print_current_name ();
1050 if (S_ISDIR (inode
->i_mode
))
1056 if (inode
&& S_ISDIR (inode
->i_mode
))
1057 recursive_check2 (ino
);
1064 recursive_check(unsigned int ino
) {
1065 struct minix_inode
* dir
;
1066 unsigned int offset
;
1069 if (!S_ISDIR(dir
->i_mode
))
1070 die(_("internal error"));
1071 if (dir
->i_size
< 2 * dirsize
) {
1072 print_current_name();
1073 printf(_(": bad directory: size<32"));
1074 errors_uncorrected
= 1;
1076 for (offset
= 0 ; offset
< dir
->i_size
; offset
+= dirsize
)
1077 check_file(dir
,offset
);
1082 recursive_check2 (unsigned int ino
) {
1083 struct minix2_inode
*dir
;
1084 unsigned int offset
;
1087 if (!S_ISDIR (dir
->i_mode
))
1088 die ("internal error");
1089 if (dir
->i_size
< 2 * dirsize
) {
1090 print_current_name ();
1091 printf (_(": bad directory: size < 32"));
1092 errors_uncorrected
= 1;
1094 for (offset
= 0; offset
< dir
->i_size
; offset
+= dirsize
)
1095 check_file2 (dir
, offset
);
1103 if (BLOCK_SIZE
*i
!= lseek(IN
, BLOCK_SIZE
*i
, SEEK_SET
))
1104 die(_("seek failed in bad_zone"));
1105 return (BLOCK_SIZE
!= read(IN
, buffer
, BLOCK_SIZE
));
1109 check_counts(void) {
1112 for (i
=1 ; i
<= INODES
; i
++) {
1113 if (!inode_in_use(i
) && Inode
[i
].i_mode
&& warn_mode
) {
1114 printf(_("Inode %d mode not cleared."),i
);
1115 if (ask(_("Clear"),1)) {
1116 Inode
[i
].i_mode
= 0;
1120 if (!inode_count
[i
]) {
1121 if (!inode_in_use(i
))
1123 printf(_("Inode %d not used, marked used in the bitmap."),i
);
1124 if (ask(_("Clear"),1))
1128 if (!inode_in_use(i
)) {
1129 printf(_("Inode %d used, marked unused in the bitmap."),
1134 if (Inode
[i
].i_nlinks
!= inode_count
[i
]) {
1135 printf(_("Inode %d (mode = %07o), i_nlinks=%d, counted=%d."),
1136 i
,Inode
[i
].i_mode
,Inode
[i
].i_nlinks
,inode_count
[i
]);
1137 if (ask(_("Set i_nlinks to count"),1)) {
1138 Inode
[i
].i_nlinks
=inode_count
[i
];
1143 for (i
=FIRSTZONE
; i
< ZONES
; i
++) {
1144 if (zone_in_use(i
) == zone_count
[i
])
1146 if (!zone_count
[i
]) {
1149 printf(_("Zone %d: marked in use, no file uses it."),i
);
1150 if (ask(_("Unmark"),1))
1154 printf(_("Zone %d: %sin use, counted=%d\n"),
1155 i
,zone_in_use(i
)?"":_("not "),zone_count
[i
]);
1161 check_counts2 (void) {
1164 for (i
= 1; i
<= INODES
; i
++) {
1165 if (!inode_in_use (i
) && Inode2
[i
].i_mode
&& warn_mode
) {
1166 printf (_("Inode %d mode not cleared."), i
);
1167 if (ask (_("Clear"), 1)) {
1168 Inode2
[i
].i_mode
= 0;
1172 if (!inode_count
[i
]) {
1173 if (!inode_in_use (i
))
1175 printf (_("Inode %d not used, marked used in the bitmap."), i
);
1176 if (ask (_("Clear"), 1))
1180 if (!inode_in_use (i
)) {
1181 printf (_("Inode %d used, marked unused in the bitmap."), i
);
1182 if (ask (_("Set"), 1))
1185 if (Inode2
[i
].i_nlinks
!= inode_count
[i
]) {
1186 printf (_("Inode %d (mode = %07o), i_nlinks=%d, counted=%d."),
1187 i
, Inode2
[i
].i_mode
, Inode2
[i
].i_nlinks
, inode_count
[i
]);
1188 if (ask (_("Set i_nlinks to count"), 1)) {
1189 Inode2
[i
].i_nlinks
= inode_count
[i
];
1194 for (i
= FIRSTZONE
; i
< ZONES
; i
++) {
1195 if (zone_in_use (i
) == zone_count
[i
])
1197 if (!zone_count
[i
]) {
1200 printf (_("Zone %d: marked in use, no file uses it."), i
);
1201 if (ask (_("Unmark"), 1))
1205 printf (_("Zone %d: %sin use, counted=%d\n"),
1206 i
, zone_in_use (i
) ? "" : _("not "), zone_count
[i
]);
1213 memset(inode_count
,0,(INODES
+ 1) * sizeof(*inode_count
));
1214 memset(zone_count
,0,ZONES
*sizeof(*zone_count
));
1215 check_zones(ROOT_INO
);
1216 recursive_check(ROOT_INO
);
1223 memset (inode_count
, 0, (INODES
+ 1) * sizeof (*inode_count
));
1224 memset (zone_count
, 0, ZONES
* sizeof (*zone_count
));
1225 check_zones2 (ROOT_INO
);
1226 recursive_check2 (ROOT_INO
);
1232 main(int argc
, char ** argv
) {
1238 program_name
= (argc
&& *argv
) ? argv
[0] : "fsck.minix";
1239 if ((p
= strrchr(program_name
, '/')) != NULL
)
1242 setlocale(LC_ALL
, "");
1243 bindtextdomain(PACKAGE
, LOCALEDIR
);
1244 textdomain(PACKAGE
);
1247 (!strcmp(argv
[1], "-V") || !strcmp(argv
[1], "--version"))) {
1248 printf(_("%s from %s\n"), program_name
, util_linux_version
);
1252 if (INODE_SIZE
* MINIX_INODES_PER_BLOCK
!= BLOCK_SIZE
)
1253 die(_("bad inode size"));
1255 if (INODE_SIZE2
* MINIX2_INODES_PER_BLOCK
!= BLOCK_SIZE
)
1256 die(_("bad v2 inode size"));
1258 while (argc
-- > 1) {
1260 if (argv
[0][0] != '-') {
1264 device_name
= argv
[0];
1265 } else while (*++argv
[0])
1266 switch (argv
[0][0]) {
1267 case 'l': list
=1; break;
1268 case 'a': automatic
=1; repair
=1; break;
1269 case 'r': automatic
=0; repair
=1; break;
1270 case 'v': verbose
=1; break;
1271 case 's': show
=1; break;
1272 case 'm': warn_mode
=1; break;
1273 case 'f': force
=1; break;
1279 check_mount(); /* trying to check a mounted filesystem? */
1280 if (repair
&& !automatic
) {
1281 if (!isatty(0) || !isatty(1))
1282 die(_("need terminal for interactive repairs"));
1284 IN
= open(device_name
,repair
?O_RDWR
:O_RDONLY
);
1286 die(_("unable to open '%s'"));
1287 for (count
=0 ; count
<3 ; count
++)
1292 * Determine whether or not we should continue with the checking.
1293 * This is based on the status of the filesystem valid and error
1294 * flags and whether or not the -f switch was specified on the
1297 if ( !(Super
.s_state
& MINIX_ERROR_FS
) &&
1298 (Super
.s_state
& MINIX_VALID_FS
) &&
1301 printf(_("%s is clean, no check.\n"), device_name
);
1305 printf(_("Forcing filesystem check on %s.\n"), device_name
);
1307 printf(_("Filesystem on %s is dirty, needs checking.\n"),\
1312 if (repair
&& !automatic
) {
1313 tcgetattr(0,&termios
);
1315 tmp
.c_lflag
&= ~(ICANON
|ECHO
);
1316 tcsetattr(0,TCSANOW
,&tmp
);
1333 for (i
=1,free
=0 ; i
<= INODES
; i
++)
1334 if (!inode_in_use(i
))
1336 printf(_("\n%6ld inodes used (%ld%%)\n"),(INODES
-free
),
1337 100*(INODES
-free
)/INODES
);
1338 for (i
=FIRSTZONE
,free
=0 ; i
< ZONES
; i
++)
1339 if (!zone_in_use(i
))
1341 printf(_("%6ld zones used (%ld%%)\n"),(ZONES
-free
),
1342 100*(ZONES
-free
)/ZONES
);
1343 printf(_("\n%6d regular files\n"
1345 "%6d character device files\n"
1346 "%6d block device files\n"
1348 "%6d symbolic links\n"
1351 regular
,directory
,chardev
,blockdev
,
1352 links
-2*directory
+1,symlinks
,total
-2*directory
+1);
1356 printf(_( "----------------------------\n"
1357 "FILE SYSTEM HAS BEEN CHANGED\n"
1358 "----------------------------\n"));
1359 for (count
=0 ; count
<3 ; count
++)
1363 write_super_block();
1365 if (repair
&& !automatic
)
1366 tcsetattr(0,TCSANOW
,&termios
);
1370 if (errors_uncorrected
)