2 * fsck.minix.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
68 * 2008-04-06 James Youngman <jay@gnu.org>
69 * - Issue better error message if we fail to open the device.
70 * - Restore terminal state if we get a fatal signal.
73 * I've had no time to add comments - hopefully the function names
74 * are comments enough. As with all file system checkers, this assumes
75 * the file system is quiescent - don't use it on a mounted device
76 * unless you can be sure nobody is writing to it (and remember that the
77 * kernel can write to it when it searches for files).
79 * Usuage: fsck [-larvsm] device
80 * -l for a listing of all the filenames
81 * -a for automatic repairs (not implemented)
82 * -r for repairs (interactive) (not implemented)
83 * -v for verbose (tells how many files)
84 * -s for super-block info
85 * -m for minix-like "mode not cleared" warnings
86 * -f force filesystem check even if filesystem marked as valid
88 * The device may be a block device or a image of one, but this isn't
89 * enforced (but it's not much fun on a character device :-).
102 #include <sys/stat.h>
106 #include "exitcodes.h"
107 #include "minix_programs.h"
109 #include "pathnames.h"
111 #include "ismounted.h"
112 #include "writeall.h"
113 #include "closestream.h"
116 #define YESNO_LENGTH 64
118 /* Global variables used in minix_programs.h inline fuctions */
120 char *super_block_buffer
;
122 static char *inode_buffer
;
124 #define Inode (((struct minix_inode *) inode_buffer) - 1)
125 #define Inode2 (((struct minix2_inode *) inode_buffer) - 1)
127 static char *device_name
;
129 static int repair
, automatic
, verbose
, list
, show
, warn_mode
, force
;
130 static int directory
, regular
, blockdev
, chardev
, links
, symlinks
, total
;
132 static int changed
; /* flags if the filesystem has been changed */
133 static int errors_uncorrected
; /* flag if some error was not corrected */
134 static size_t dirsize
= 16;
135 static size_t namelen
= 14;
136 static struct termios termios
;
137 static volatile sig_atomic_t termios_set
;
141 static int name_depth
;
142 static char name_list
[MAX_DEPTH
][MINIX_NAME_MAX
+ 1];
144 /* Copy of the previous, just for error reporting - see get_current_name. This
145 * is a waste of 12kB or so. */
146 static char current_name
[MAX_DEPTH
* (MINIX_NAME_MAX
+ 1) + 1];
148 #define MAGIC (Super.s_magic)
150 static unsigned char *inode_count
= NULL
;
151 static unsigned char *zone_count
= NULL
;
153 static void recursive_check(unsigned int ino
);
154 static void recursive_check2(unsigned int ino
);
156 static char *inode_map
;
157 static char *zone_map
;
159 #define inode_in_use(x) (isset(inode_map,(x)) != 0)
160 #define zone_in_use(x) (isset(zone_map,(x)-get_first_zone()+1) != 0)
162 #define mark_inode(x) (setbit(inode_map,(x)),changed=1)
163 #define unmark_inode(x) (clrbit(inode_map,(x)),changed=1)
165 #define mark_zone(x) (setbit(zone_map,(x)-get_first_zone()+1),changed=1)
166 #define unmark_zone(x) (clrbit(zone_map,(x)-get_first_zone()+1),changed=1)
171 tcsetattr(0, TCSANOW
, &termios
);
176 /* We received a fatal signal. Reset the terminal. Also reset the
177 * signal handler and re-send the signal, so that the parent process
178 * knows which signal actually caused our death. */
179 signal(sig
, SIG_DFL
);
192 fputs(USAGE_HEADER
, stderr
);
194 _(" %s [options] <device>\n"), program_invocation_short_name
);
195 fputs(USAGE_OPTIONS
, stderr
);
196 fputs(_(" -l list all filenames\n"), stderr
);
197 fputs(_(" -a automatic repair\n"), stderr
);
198 fputs(_(" -r interactive repair\n"), stderr
);
199 fputs(_(" -v be verbose\n"), stderr
);
200 fputs(_(" -s output super-block information\n"), stderr
);
201 fputs(_(" -m activate mode not cleared warnings\n"), stderr
);
202 fputs(_(" -f force check\n"), stderr
);
203 fputs(USAGE_SEPARATOR
, stderr
);
204 fputs(USAGE_VERSION
, stderr
);
205 fprintf(stderr
, USAGE_MAN_TAIL("fsck.minix(8)"));
206 leave(FSCK_EX_USAGE
);
209 static void die(const char *fmt
, ...)
210 __attribute__ ((__format__(__printf__
, 1, 2)));
213 die(const char *fmt
, ...) {
216 fprintf(stderr
, "%s: ", program_invocation_short_name
);
218 vfprintf(stderr
, fmt
, ap
);
221 leave(FSCK_EX_ERROR
);
224 /* This simply goes through the file-name data and prints out the current file. */
226 get_current_name(void) {
231 while (i
< name_depth
) {
244 ask(const char *string
, int def
) {
246 char input
[YESNO_LENGTH
];
250 errors_uncorrected
= 1;
256 errors_uncorrected
= 1;
259 /* TRANSLATORS: these yes no questions uses rpmatch(), and should be
261 printf(def
? _("%s (y/n)? ") : _("%s (n/y)? "), string
);
263 fgets(input
, YESNO_LENGTH
, stdin
);
264 resp
= rpmatch(input
);
281 errors_uncorrected
= 1;
286 /* Make certain that we aren't checking a filesystem that is on a mounted
287 * partition. Code adapted from e2fsck, Copyright (C) 1993, 1994 Theodore
288 * Ts'o. Also licensed under GPL. */
293 if (!is_mounted(device_name
))
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"));
308 /* check_zone_nr checks to see that *nr is a valid zone nr. If it isn't, it
309 * will possibly be repaired. Check_zone_nr sets *corrected if an error was
310 * corrected, and returns the zone (0 for no zone or a bad zone-number). */
312 check_zone_nr(unsigned short *nr
, int *corrected
) {
316 if (*nr
< get_first_zone()) {
318 printf(_("Zone nr < FIRSTZONE in file `%s'."), current_name
);
319 } else if (*nr
>= get_nzones()) {
321 printf(_("Zone nr >= ZONES in file `%s'."), current_name
);
325 if (ask(_("Remove block"), 1)) {
333 check_zone_nr2(unsigned int *nr
, int *corrected
) {
337 if (*nr
< get_first_zone()) {
339 printf(_("Zone nr < FIRSTZONE in file `%s'."), current_name
);
340 } else if (*nr
>= get_nzones()) {
342 printf(_("Zone nr >= ZONES in file `%s'."), current_name
);
346 if (ask(_("Remove block"), 1)) {
353 /* read-block reads block nr into the buffer at addr. */
355 read_block(unsigned int nr
, char *addr
) {
357 memset(addr
, 0, MINIX_BLOCK_SIZE
);
360 if (MINIX_BLOCK_SIZE
* nr
!= lseek(IN
, MINIX_BLOCK_SIZE
* nr
, SEEK_SET
)) {
362 printf(_("Read error: unable to seek to block in file '%s'\n"),
364 memset(addr
, 0, MINIX_BLOCK_SIZE
);
365 errors_uncorrected
= 1;
366 } else if (MINIX_BLOCK_SIZE
!= read(IN
, addr
, MINIX_BLOCK_SIZE
)) {
368 printf(_("Read error: bad block in file '%s'\n"), current_name
);
369 memset(addr
, 0, MINIX_BLOCK_SIZE
);
370 errors_uncorrected
= 1;
374 /* write_block writes block nr to disk. */
376 write_block(unsigned int nr
, char *addr
) {
379 if (nr
< get_first_zone() || nr
>= get_nzones()) {
380 printf(_("Internal error: trying to write bad block\n"
381 "Write request ignored\n"));
382 errors_uncorrected
= 1;
385 if (MINIX_BLOCK_SIZE
* nr
!= lseek(IN
, MINIX_BLOCK_SIZE
* nr
, SEEK_SET
))
386 die(_("seek failed in write_block"));
387 if (MINIX_BLOCK_SIZE
!= write(IN
, addr
, MINIX_BLOCK_SIZE
)) {
389 printf(_("Write error: bad block in file '%s'\n"),
391 errors_uncorrected
= 1;
395 /* map-block calculates the absolute block nr of a block in a file. It sets
396 * 'changed' if the inode has needed changing, and re-writes any indirect
397 * blocks with errors. */
399 map_block(struct minix_inode
*inode
, unsigned int blknr
) {
400 unsigned short ind
[MINIX_BLOCK_SIZE
>> 1];
401 unsigned short dind
[MINIX_BLOCK_SIZE
>> 1];
402 int blk_chg
, block
, result
;
405 return check_zone_nr(inode
->i_zone
+ blknr
, &changed
);
408 block
= check_zone_nr(inode
->i_zone
+ 7, &changed
);
409 read_block(block
, (char *)ind
);
411 result
= check_zone_nr(blknr
+ ind
, &blk_chg
);
413 write_block(block
, (char *)ind
);
417 block
= check_zone_nr(inode
->i_zone
+ 8, &changed
);
418 read_block(block
, (char *)dind
);
420 result
= check_zone_nr(dind
+ (blknr
/ 512), &blk_chg
);
422 write_block(block
, (char *)dind
);
424 read_block(block
, (char *)ind
);
426 result
= check_zone_nr(ind
+ (blknr
% 512), &blk_chg
);
428 write_block(block
, (char *)ind
);
433 map_block2(struct minix2_inode
*inode
, unsigned int blknr
) {
434 unsigned int ind
[MINIX_BLOCK_SIZE
>> 2];
435 unsigned int dind
[MINIX_BLOCK_SIZE
>> 2];
436 unsigned int tind
[MINIX_BLOCK_SIZE
>> 2];
437 int blk_chg
, block
, result
;
440 return check_zone_nr2(inode
->i_zone
+ blknr
, &changed
);
443 block
= check_zone_nr2(inode
->i_zone
+ 7, &changed
);
444 read_block(block
, (char *)ind
);
446 result
= check_zone_nr2(blknr
+ ind
, &blk_chg
);
448 write_block(block
, (char *)ind
);
452 if (blknr
< 256 * 256) {
453 block
= check_zone_nr2(inode
->i_zone
+ 8, &changed
);
454 read_block(block
, (char *)dind
);
456 result
= check_zone_nr2(dind
+ blknr
/ 256, &blk_chg
);
458 write_block(block
, (char *)dind
);
460 read_block(block
, (char *)ind
);
462 result
= check_zone_nr2(ind
+ blknr
% 256, &blk_chg
);
464 write_block(block
, (char *)ind
);
468 block
= check_zone_nr2(inode
->i_zone
+ 9, &changed
);
469 read_block(block
, (char *)tind
);
471 result
= check_zone_nr2(tind
+ blknr
/ (256 * 256), &blk_chg
);
473 write_block(block
, (char *)tind
);
475 read_block(block
, (char *)dind
);
477 result
= check_zone_nr2(dind
+ (blknr
/ 256) % 256, &blk_chg
);
479 write_block(block
, (char *)dind
);
481 read_block(block
, (char *)ind
);
483 result
= check_zone_nr2(ind
+ blknr
% 256, &blk_chg
);
485 write_block(block
, (char *)ind
);
490 write_super_block(void) {
491 /* Set the state of the filesystem based on whether or not there are
492 * uncorrected errors. The filesystem valid flag is unconditionally
493 * set if we get this far. */
494 Super
.s_state
|= MINIX_VALID_FS
;
495 if (errors_uncorrected
)
496 Super
.s_state
|= MINIX_ERROR_FS
;
498 Super
.s_state
&= ~MINIX_ERROR_FS
;
500 if (MINIX_BLOCK_SIZE
!= lseek(IN
, MINIX_BLOCK_SIZE
, SEEK_SET
))
501 die(_("seek failed in write_super_block"));
502 if (MINIX_BLOCK_SIZE
!= write(IN
, super_block_buffer
, MINIX_BLOCK_SIZE
))
503 die(_("unable to write super-block"));
510 unsigned long buffsz
= get_inode_buffer_size();
511 unsigned long imaps
= get_nimaps();
512 unsigned long zmaps
= get_nzmaps();
514 if (write_all(IN
, inode_map
, imaps
* MINIX_BLOCK_SIZE
))
515 die(_("Unable to write inode map"));
517 if (write_all(IN
, zone_map
, zmaps
* MINIX_BLOCK_SIZE
))
518 die(_("Unable to write zone map"));
520 if (write_all(IN
, inode_buffer
, buffsz
))
521 die(_("Unable to write inodes"));
527 char blk
[MINIX_BLOCK_SIZE
];
531 block
= Inode2
[ROOT_INO
].i_zone
[0];
533 block
= Inode
[ROOT_INO
].i_zone
[0];
534 read_block(block
, blk
);
536 for (size
= 16; size
< MINIX_BLOCK_SIZE
; size
<<= 1) {
537 if (strcmp(blk
+ size
+ 2, "..") == 0) {
547 read_superblock(void) {
548 if (MINIX_BLOCK_SIZE
!= lseek(IN
, MINIX_BLOCK_SIZE
, SEEK_SET
))
549 die(_("seek failed"));
551 super_block_buffer
= calloc(1, MINIX_BLOCK_SIZE
);
552 if (!super_block_buffer
)
553 die(_("unable to alloc buffer for superblock"));
555 if (MINIX_BLOCK_SIZE
!= read(IN
, super_block_buffer
, MINIX_BLOCK_SIZE
))
556 die(_("unable to read super block"));
557 if (MAGIC
== MINIX_SUPER_MAGIC
) {
561 } else if (MAGIC
== MINIX_SUPER_MAGIC2
) {
565 } else if (MAGIC
== MINIX2_SUPER_MAGIC
) {
569 } else if (MAGIC
== MINIX2_SUPER_MAGIC2
) {
574 die(_("bad magic number in super-block"));
575 if (get_zone_size() != 0 || MINIX_BLOCK_SIZE
!= 1024)
576 die(_("Only 1k blocks/zones supported"));
577 if (get_nimaps() * MINIX_BLOCK_SIZE
* 8 < get_ninodes() + 1)
578 die(_("bad s_imap_blocks field in super-block"));
579 if (get_nzmaps() * MINIX_BLOCK_SIZE
* 8 <
580 get_nzones() - get_first_zone() + 1)
581 die(_("bad s_zmap_blocks field in super-block"));
586 unsigned long inodes
= get_ninodes();
587 unsigned long buffsz
= get_inode_buffer_size();
588 unsigned long norm_first_zone
= first_zone_data();
589 unsigned long first_zone
= get_first_zone();
590 unsigned long zones
= get_nzones();
591 unsigned long imaps
= get_nimaps();
592 unsigned long zmaps
= get_nzmaps();
595 inode_map
= malloc(imaps
* MINIX_BLOCK_SIZE
);
597 die(_("Unable to allocate buffer for inode map"));
598 zone_map
= malloc(zmaps
* MINIX_BLOCK_SIZE
);
600 die(_("Unable to allocate buffer for zone map"));
601 inode_buffer
= malloc(buffsz
);
603 die(_("Unable to allocate buffer for inodes"));
604 inode_count
= calloc(1, inodes
+ 1);
606 die(_("Unable to allocate buffer for inode count"));
607 zone_count
= calloc(1, zones
);
609 die(_("Unable to allocate buffer for zone count"));
611 rc
= read(IN
, inode_map
, imaps
* MINIX_BLOCK_SIZE
);
612 if (rc
< 0 || imaps
* MINIX_BLOCK_SIZE
!= (size_t) rc
)
613 die(_("Unable to read inode map"));
615 rc
= read(IN
, zone_map
, zmaps
* MINIX_BLOCK_SIZE
);
616 if (rc
< 0 || zmaps
* MINIX_BLOCK_SIZE
!= (size_t) rc
)
617 die(_("Unable to read zone map"));
619 rc
= read(IN
, inode_buffer
, buffsz
);
620 if (rc
< 0 || buffsz
!= (size_t) rc
)
621 die(_("Unable to read inodes"));
622 if (norm_first_zone
!= first_zone
) {
623 printf(_("Warning: Firstzone != Norm_firstzone\n"));
624 errors_uncorrected
= 1;
628 printf(_("%ld inodes\n"), inodes
);
629 printf(_("%ld blocks\n"), zones
);
630 printf(_("Firstdatazone=%ld (%ld)\n"), first_zone
, norm_first_zone
);
631 printf(_("Zonesize=%d\n"), MINIX_BLOCK_SIZE
<< get_zone_size());
632 printf(_("Maxsize=%ld\n"), get_max_size());
633 printf(_("Filesystem state=%d\n"), Super
.s_state
);
634 printf(_("namelen=%zd\n\n"), namelen
);
638 static struct minix_inode
*
639 get_inode(unsigned int nr
) {
640 struct minix_inode
*inode
;
642 if (!nr
|| nr
> get_ninodes())
646 if (!inode_count
[nr
]) {
647 if (!inode_in_use(nr
)) {
649 printf(_("Inode %d marked unused, "
650 "but used for file '%s'\n"), nr
, current_name
);
652 if (ask(_("Mark in use"), 1))
655 errors_uncorrected
= 1;
658 if (S_ISDIR(inode
->i_mode
))
660 else if (S_ISREG(inode
->i_mode
))
662 else if (S_ISCHR(inode
->i_mode
))
664 else if (S_ISBLK(inode
->i_mode
))
666 else if (S_ISLNK(inode
->i_mode
))
668 else if (S_ISSOCK(inode
->i_mode
))
670 else if (S_ISFIFO(inode
->i_mode
))
674 printf(_("The file `%s' has mode %05o\n"),
675 current_name
, inode
->i_mode
);
680 if (!++inode_count
[nr
]) {
681 printf(_("Warning: inode count too big.\n"));
683 errors_uncorrected
= 1;
688 static struct minix2_inode
*
689 get_inode2(unsigned int nr
) {
690 struct minix2_inode
*inode
;
692 if (!nr
|| nr
> get_ninodes())
696 if (!inode_count
[nr
]) {
697 if (!inode_in_use(nr
)) {
699 printf(_("Inode %d marked unused, "
700 "but used for file '%s'\n"), nr
, current_name
);
702 if (ask(_("Mark in use"), 1))
705 errors_uncorrected
= 1;
708 if (S_ISDIR(inode
->i_mode
))
710 else if (S_ISREG(inode
->i_mode
))
712 else if (S_ISCHR(inode
->i_mode
))
714 else if (S_ISBLK(inode
->i_mode
))
716 else if (S_ISLNK(inode
->i_mode
))
718 else if (S_ISSOCK(inode
->i_mode
)) ;
719 else if (S_ISFIFO(inode
->i_mode
)) ;
722 printf(_("The file `%s' has mode %05o\n"),
723 current_name
, inode
->i_mode
);
727 if (!++inode_count
[nr
]) {
728 printf(_("Warning: inode count too big.\n"));
730 errors_uncorrected
= 1;
737 struct minix_inode
*inode
= Inode
+ ROOT_INO
;
739 if (!inode
|| !S_ISDIR(inode
->i_mode
))
740 die(_("root inode isn't a directory"));
745 struct minix2_inode
*inode
= Inode2
+ ROOT_INO
;
747 if (!inode
|| !S_ISDIR(inode
->i_mode
))
748 die(_("root inode isn't a directory"));
752 add_zone(unsigned short *znr
, int *corrected
) {
755 block
= check_zone_nr(znr
, corrected
);
758 if (zone_count
[block
]) {
760 printf(_("Block has been used before. Now in file `%s'."),
762 if (ask(_("Clear"), 1)) {
770 if (!zone_in_use(block
)) {
772 printf(_("Block %d in file `%s' is marked not in use."),
773 block
, current_name
);
774 if (ask(_("Correct"), 1))
777 if (!++zone_count
[block
])
783 add_zone2(unsigned int *znr
, int *corrected
) {
786 block
= check_zone_nr2(znr
, corrected
);
789 if (zone_count
[block
]) {
791 printf(_("Block has been used before. Now in file `%s'."),
793 if (ask(_("Clear"), 1)) {
801 if (!zone_in_use(block
)) {
803 printf(_("Block %d in file `%s' is marked not in use."),
804 block
, current_name
);
805 if (ask(_("Correct"), 1))
808 if (!++zone_count
[block
])
814 add_zone_ind(unsigned short *znr
, int *corrected
) {
815 static char blk
[MINIX_BLOCK_SIZE
];
819 block
= add_zone(znr
, corrected
);
822 read_block(block
, blk
);
823 for (i
= 0; i
< (MINIX_BLOCK_SIZE
>> 1); i
++)
824 add_zone(i
+ (unsigned short *)blk
, &chg_blk
);
826 write_block(block
, blk
);
830 add_zone_ind2(unsigned int *znr
, int *corrected
) {
831 static char blk
[MINIX_BLOCK_SIZE
];
835 block
= add_zone2(znr
, corrected
);
838 read_block(block
, blk
);
839 for (i
= 0; i
< MINIX_BLOCK_SIZE
>> 2; i
++)
840 add_zone2(i
+ (unsigned int *)blk
, &chg_blk
);
842 write_block(block
, blk
);
846 add_zone_dind(unsigned short *znr
, int *corrected
) {
847 static char blk
[MINIX_BLOCK_SIZE
];
851 block
= add_zone(znr
, corrected
);
854 read_block(block
, blk
);
855 for (i
= 0; i
< (MINIX_BLOCK_SIZE
>> 1); i
++)
856 add_zone_ind(i
+ (unsigned short *)blk
, &blk_chg
);
858 write_block(block
, blk
);
862 add_zone_dind2(unsigned int *znr
, int *corrected
) {
863 static char blk
[MINIX_BLOCK_SIZE
];
867 block
= add_zone2(znr
, corrected
);
870 read_block(block
, blk
);
871 for (i
= 0; i
< MINIX_BLOCK_SIZE
>> 2; i
++)
872 add_zone_ind2(i
+ (unsigned int *)blk
, &blk_chg
);
874 write_block(block
, blk
);
878 add_zone_tind2(unsigned int *znr
, int *corrected
) {
879 static char blk
[MINIX_BLOCK_SIZE
];
883 block
= add_zone2(znr
, corrected
);
886 read_block(block
, blk
);
887 for (i
= 0; i
< MINIX_BLOCK_SIZE
>> 2; i
++)
888 add_zone_dind2(i
+ (unsigned int *)blk
, &blk_chg
);
890 write_block(block
, blk
);
894 check_zones(unsigned int i
) {
895 struct minix_inode
*inode
;
897 if (!i
|| i
> get_ninodes())
899 if (inode_count
[i
] > 1) /* have we counted this file already? */
902 if (!S_ISDIR(inode
->i_mode
) && !S_ISREG(inode
->i_mode
) &&
903 !S_ISLNK(inode
->i_mode
))
905 for (i
= 0; i
< 7; i
++)
906 add_zone(i
+ inode
->i_zone
, &changed
);
907 add_zone_ind(7 + inode
->i_zone
, &changed
);
908 add_zone_dind(8 + inode
->i_zone
, &changed
);
912 check_zones2(unsigned int i
) {
913 struct minix2_inode
*inode
;
915 if (!i
|| i
> get_ninodes())
917 if (inode_count
[i
] > 1) /* have we counted this file already? */
920 if (!S_ISDIR(inode
->i_mode
) && !S_ISREG(inode
->i_mode
)
921 && !S_ISLNK(inode
->i_mode
))
923 for (i
= 0; i
< 7; i
++)
924 add_zone2(i
+ inode
->i_zone
, &changed
);
925 add_zone_ind2(7 + inode
->i_zone
, &changed
);
926 add_zone_dind2(8 + inode
->i_zone
, &changed
);
927 add_zone_tind2(9 + inode
->i_zone
, &changed
);
931 check_file(struct minix_inode
*dir
, unsigned int offset
) {
932 static char blk
[MINIX_BLOCK_SIZE
];
933 struct minix_inode
*inode
;
938 block
= map_block(dir
, offset
/ MINIX_BLOCK_SIZE
);
939 read_block(block
, blk
);
940 name
= blk
+ (offset
% MINIX_BLOCK_SIZE
) + 2;
941 ino
= *(unsigned short *)(name
- 2);
942 if (ino
> get_ninodes()) {
944 printf(_("The directory '%s' contains a bad inode number "
945 "for file '%.*s'."), current_name
, (int)namelen
, name
);
946 if (ask(_(" Remove"), 1)) {
947 *(unsigned short *)(name
- 2) = 0;
948 write_block(block
, blk
);
952 if (name_depth
< MAX_DEPTH
)
953 strncpy(name_list
[name_depth
], name
, namelen
);
955 inode
= get_inode(ino
);
958 if (!inode
|| strcmp(".", name
)) {
960 printf(_("%s: bad directory: '.' isn't first\n"),
962 errors_uncorrected
= 1;
966 if (offset
== dirsize
) {
967 if (!inode
|| strcmp("..", name
)) {
969 printf(_("%s: bad directory: '..' isn't second\n"),
971 errors_uncorrected
= 1;
977 if (name_depth
< MAX_DEPTH
)
978 strncpy(name_list
[name_depth
], name
, namelen
);
982 printf("%6d %07o %3d ", ino
,
983 inode
->i_mode
, inode
->i_nlinks
);
985 printf("%s", current_name
);
986 if (S_ISDIR(inode
->i_mode
))
992 if (inode
&& S_ISDIR(inode
->i_mode
))
993 recursive_check(ino
);
999 check_file2(struct minix2_inode
*dir
, unsigned int offset
) {
1000 static char blk
[MINIX_BLOCK_SIZE
];
1001 struct minix2_inode
*inode
;
1006 block
= map_block2(dir
, offset
/ MINIX_BLOCK_SIZE
);
1007 read_block(block
, blk
);
1008 name
= blk
+ (offset
% MINIX_BLOCK_SIZE
) + 2;
1009 ino
= *(unsigned short *)(name
- 2);
1010 if (ino
> get_ninodes()) {
1012 printf(_("The directory '%s' contains a bad inode number "
1013 "for file '%.*s'."), current_name
, (int)namelen
, name
);
1014 if (ask(_(" Remove"), 1)) {
1015 *(unsigned short *)(name
- 2) = 0;
1016 write_block(block
, blk
);
1020 if (name_depth
< MAX_DEPTH
)
1021 strncpy(name_list
[name_depth
], name
, namelen
);
1023 inode
= get_inode2(ino
);
1026 if (!inode
|| strcmp(".", name
)) {
1028 printf(_("%s: bad directory: '.' isn't first\n"),
1030 errors_uncorrected
= 1;
1034 if (offset
== dirsize
) {
1035 if (!inode
|| strcmp("..", name
)) {
1037 printf(_("%s: bad directory: '..' isn't second\n"),
1039 errors_uncorrected
= 1;
1048 printf("%6zd %07o %3d ", ino
, inode
->i_mode
,
1051 printf("%s", current_name
);
1052 if (S_ISDIR(inode
->i_mode
))
1058 if (inode
&& S_ISDIR(inode
->i_mode
))
1059 recursive_check2(ino
);
1065 recursive_check(unsigned int ino
) {
1066 struct minix_inode
*dir
;
1067 unsigned int offset
;
1070 if (!S_ISDIR(dir
->i_mode
))
1071 die(_("internal error"));
1072 if (dir
->i_size
< 2 * dirsize
) {
1074 printf(_("%s: bad directory: size < 32"), current_name
);
1075 errors_uncorrected
= 1;
1077 for (offset
= 0; offset
< dir
->i_size
; offset
+= dirsize
)
1078 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
) {
1091 printf(_("%s: bad directory: size < 32"), current_name
);
1092 errors_uncorrected
= 1;
1094 for (offset
= 0; offset
< dir
->i_size
; offset
+= dirsize
)
1095 check_file2(dir
, offset
);
1102 if (MINIX_BLOCK_SIZE
* i
!= lseek(IN
, MINIX_BLOCK_SIZE
* i
, SEEK_SET
))
1103 die(_("seek failed in bad_zone"));
1104 return (MINIX_BLOCK_SIZE
!= read(IN
, buffer
, MINIX_BLOCK_SIZE
));
1108 check_counts(void) {
1111 for (i
= 1; i
<= get_ninodes(); i
++) {
1112 if (!inode_in_use(i
) && Inode
[i
].i_mode
&& warn_mode
) {
1113 printf(_("Inode %lu mode not cleared."), i
);
1114 if (ask(_("Clear"), 1)) {
1115 Inode
[i
].i_mode
= 0;
1119 if (!inode_count
[i
]) {
1120 if (!inode_in_use(i
))
1122 printf(_("Inode %lu not used, marked used in the bitmap."), i
);
1123 if (ask(_("Clear"), 1))
1127 if (!inode_in_use(i
)) {
1128 printf(_("Inode %lu used, marked unused in the bitmap."), i
);
1129 if (ask(_("Set"), 1))
1132 if (Inode
[i
].i_nlinks
!= inode_count
[i
]) {
1133 printf(_("Inode %lu (mode = %07o), i_nlinks=%d, counted=%d."),
1134 i
, Inode
[i
].i_mode
, Inode
[i
].i_nlinks
,
1136 if (ask(_("Set i_nlinks to count"), 1)) {
1137 Inode
[i
].i_nlinks
= inode_count
[i
];
1142 for (i
= get_first_zone(); i
< get_nzones(); i
++) {
1143 if (zone_in_use(i
) == zone_count
[i
])
1145 if (!zone_count
[i
]) {
1148 printf(_("Zone %lu: marked in use, no file uses it."),
1150 if (ask(_("Unmark"), 1))
1155 printf(_("Zone %lu: in use, counted=%d\n"),
1158 printf(_("Zone %lu: not in use, counted=%d\n"),
1164 check_counts2(void) {
1167 for (i
= 1; i
<= get_ninodes(); i
++) {
1168 if (!inode_in_use(i
) && Inode2
[i
].i_mode
&& warn_mode
) {
1169 printf(_("Inode %lu mode not cleared."), i
);
1170 if (ask(_("Clear"), 1)) {
1171 Inode2
[i
].i_mode
= 0;
1175 if (!inode_count
[i
]) {
1176 if (!inode_in_use(i
))
1178 printf(_("Inode %lu not used, marked used in the bitmap."), i
);
1179 if (ask(_("Clear"), 1))
1183 if (!inode_in_use(i
)) {
1184 printf(_("Inode %lu used, marked unused in the bitmap."), i
);
1185 if (ask(_("Set"), 1))
1188 if (Inode2
[i
].i_nlinks
!= inode_count
[i
]) {
1189 printf(_("Inode %lu (mode = %07o), i_nlinks=%d, counted=%d."),
1190 i
, Inode2
[i
].i_mode
, Inode2
[i
].i_nlinks
,
1192 if (ask(_("Set i_nlinks to count"), 1)) {
1193 Inode2
[i
].i_nlinks
= inode_count
[i
];
1198 for (i
= get_first_zone(); i
< get_nzones(); i
++) {
1199 if (zone_in_use(i
) == zone_count
[i
])
1201 if (!zone_count
[i
]) {
1204 printf(_("Zone %lu: marked in use, no file uses it."),
1206 if (ask(_("Unmark"), 1))
1211 printf(_("Zone %lu: in use, counted=%d\n"),
1214 printf(_("Zone %lu: not in use, counted=%d\n"),
1221 memset(inode_count
, 0, (get_ninodes() + 1) * sizeof(*inode_count
));
1222 memset(zone_count
, 0, get_nzones() * sizeof(*zone_count
));
1223 check_zones(ROOT_INO
);
1224 recursive_check(ROOT_INO
);
1230 memset(inode_count
, 0, (get_ninodes() + 1) * sizeof(*inode_count
));
1231 memset(zone_count
, 0, get_nzones() * sizeof(*zone_count
));
1232 check_zones2(ROOT_INO
);
1233 recursive_check2(ROOT_INO
);
1238 main(int argc
, char **argv
) {
1243 setlocale(LC_ALL
, "");
1244 bindtextdomain(PACKAGE
, LOCALEDIR
);
1245 textdomain(PACKAGE
);
1246 atexit(close_stdout
);
1249 (!strcmp(argv
[1], "-V") || !strcmp(argv
[1], "--version"))) {
1250 printf(UTIL_LINUX_VERSION
);
1254 if (INODE_SIZE
* MINIX_INODES_PER_BLOCK
!= MINIX_BLOCK_SIZE
)
1255 die(_("bad inode size"));
1256 if (INODE2_SIZE
* MINIX2_INODES_PER_BLOCK
!= MINIX_BLOCK_SIZE
)
1257 die(_("bad v2 inode size"));
1259 while (argc
-- > 1) {
1261 if (argv
[0][0] != '-') {
1265 device_name
= argv
[0];
1268 switch (argv
[0][0]) {
1298 check_mount(); /* trying to check a mounted filesystem? */
1299 if (repair
&& !automatic
) {
1300 if (!isatty(0) || !isatty(1))
1301 die(_("need terminal for interactive repairs"));
1303 IN
= open(device_name
, repair
? O_RDWR
: O_RDONLY
);
1305 die(_("unable to open '%s': %s"), device_name
, strerror(errno
));
1306 for (count
= 0; count
< 3; count
++)
1310 /* Determine whether or not we should continue with the checking. This
1311 * is based on the status of the filesystem valid and error flags and
1312 * whether or not the -f switch was specified on the command line. */
1313 if (!(Super
.s_state
& MINIX_ERROR_FS
) &&
1314 (Super
.s_state
& MINIX_VALID_FS
) && !force
) {
1316 printf(_("%s is clean, no check.\n"), device_name
);
1319 printf(_("Forcing filesystem check on %s.\n"), device_name
);
1321 printf(_("Filesystem on %s is dirty, needs checking.\n"),
1326 /* Restore the terminal state on fatal signals. We don't do this for
1327 * SIGALRM, SIGUSR1 or SIGUSR2. */
1328 signal(SIGINT
, fatalsig
);
1329 signal(SIGQUIT
, fatalsig
);
1330 signal(SIGTERM
, fatalsig
);
1332 if (repair
&& !automatic
) {
1333 tcgetattr(0, &termios
);
1335 tmp
.c_lflag
&= ~(ICANON
| ECHO
);
1336 tcsetattr(0, TCSANOW
, &tmp
);
1340 if (fs_version
== 2) {
1348 unsigned long i
, free
;
1350 for (i
= 1, free
= 0; i
<= get_ninodes(); i
++)
1351 if (!inode_in_use(i
))
1353 printf(_("\n%6ld inodes used (%ld%%)\n"),
1354 (get_ninodes() - free
),
1355 100 * (get_ninodes() - free
) / get_ninodes());
1356 for (i
= get_first_zone(), free
= 0; i
< get_nzones(); i
++)
1357 if (!zone_in_use(i
))
1359 printf(_("%6ld zones used (%ld%%)\n"), (get_nzones() - free
),
1360 100 * (get_nzones() - free
) / get_nzones());
1361 printf(_("\n%6d regular files\n"
1363 "%6d character device files\n"
1364 "%6d block device files\n"
1366 "%6d symbolic links\n"
1369 regular
, directory
, chardev
, blockdev
,
1370 links
- 2 * directory
+ 1, symlinks
,
1371 total
- 2 * directory
+ 1);
1375 printf(_("----------------------------\n"
1376 "FILE SYSTEM HAS BEEN CHANGED\n"
1377 "----------------------------\n"));
1378 for (count
= 0; count
< 3; count
++)
1381 write_super_block();
1383 if (repair
&& !automatic
)
1384 tcsetattr(0, TCSANOW
, &termios
);
1388 if (errors_uncorrected
)