2 * e2fsck.c - a consistency checker for the new extended file system.
4 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be
5 * redistributed under the terms of the GNU Public License.
8 /* Usage: e2fsck [-dfpnsvy] device
9 * -d -- debugging this program
10 * -f -- check the fs even if it is marked valid
11 * -p -- "preen" the filesystem
12 * -n -- open the filesystem r/o mode; never try to fix problems
13 * -v -- verbose (tells how many files)
14 * -y -- always answer yes to questions
16 * The device may be a block device or a image of one, but this isn't
17 * enforced (but it's not much fun on a character device :-).
35 #include <sys/ioctl.h>
38 #include "et/com_err.h"
40 #include "../version.h"
42 extern int isatty(int);
44 const char * program_name = "e2fsck";
45 const char * device_name = NULL;
46 const char * filesystem_name = NULL;
48 /* Command line options */
51 int tflag = 0; /* Do timing */
52 int cflag = 0; /* check disk */
55 int inode_buffer_blocks = 0;
62 int invalid_bitmaps = 0;
63 static int show_version_only = 0;
65 static int replace_bad_blocks = 0;
66 static char *bad_blocks_file = 0;
68 static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
70 struct resource_track global_rtrack;
72 static int root_filesystem = 0;
73 static int read_only_root = 0;
75 int *invalid_inode_bitmap;
76 int *invalid_block_bitmap;
77 int *invalid_inode_table;
78 int restart_e2fsck = 0;
80 static void usage(NOARGS)
83 "Usage: %s [-panyrcdfvtFV] [-b superblock] [-B blocksize]\n"
84 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
85 "\t\t[-l|-L bad_blocks_file] device\n", program_name);
89 static void show_stats(ext2_filsys fs)
91 int inodes, inodes_used, blocks, blocks_used;
93 int num_files, num_links;
96 dir_links = 2 * fs_directory_count - 1;
97 num_files = fs_total_count - dir_links;
98 num_links = fs_links_count - dir_links;
99 inodes = fs->super->s_inodes_count;
100 inodes_used = (fs->super->s_inodes_count -
101 fs->super->s_free_inodes_count);
102 blocks = fs->super->s_blocks_count;
103 blocks_used = (fs->super->s_blocks_count -
104 fs->super->s_free_blocks_count);
106 frag_percent = (10000 * fs_fragmented) / inodes_used;
107 frag_percent = (frag_percent + 5) / 10;
110 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
111 device_name, inodes_used, inodes,
112 frag_percent / 10, frag_percent % 10,
113 blocks_used, blocks);
116 printf ("\n%8d inode%s used (%d%%)\n", inodes_used,
117 (inodes_used != 1) ? "s" : "",
118 100 * inodes_used / inodes);
119 printf ("%8d non-contiguous inodes (%0d.%d%%)\n",
120 fs_fragmented, frag_percent / 10, frag_percent % 10);
121 printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n",
122 fs_ind_count, fs_dind_count, fs_tind_count);
123 printf ("%8d block%s used (%d%%)\n"
124 "%8d bad block%s\n", blocks_used,
125 (blocks_used != 1) ? "s" : "",
126 100 * blocks_used / blocks, fs_badblocks_count,
127 fs_badblocks_count != 1 ? "s" : "");
128 printf ("\n%8d regular file%s\n"
130 "%8d character device file%s\n"
131 "%8d block device file%s\n"
134 "%8d symbolic link%s (%d fast symbolic link%s)\n"
138 fs_regular_count, (fs_regular_count != 1) ? "s" : "",
139 fs_directory_count, (fs_directory_count != 1) ? "ies" : "y",
140 fs_chardev_count, (fs_chardev_count != 1) ? "s" : "",
141 fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "",
142 fs_fifo_count, (fs_fifo_count != 1) ? "s" : "",
143 fs_links_count - dir_links,
144 ((fs_links_count - dir_links) != 1) ? "s" : "",
145 fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "",
146 fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "",
147 fs_sockets_count, (fs_sockets_count != 1) ? "s" : "",
148 fs_total_count - dir_links,
149 ((fs_total_count - dir_links) != 1) ? "s" : "");
152 static void check_mount(NOARGS)
155 int mount_flags, cont, fd;
157 retval = ext2fs_check_if_mounted(filesystem_name, &mount_flags);
159 com_err("ext2fs_check_if_mount", retval,
160 "while determining whether %s is mounted.",
164 if (!(mount_flags & EXT2_MF_MOUNTED))
167 #if (defined(__linux__) && defined(HAVE_MNTENT_H))
169 * If the root is mounted read-only, then /etc/mtab is
170 * probably not correct; so we won't issue a warning based on
173 fd = open(MOUNTED, O_RDWR);
182 printf("Warning! %s is mounted.\n", device_name);
186 printf ("%s is mounted. ", device_name);
187 if (isatty (0) && isatty (1))
188 cont = ask_yn("Do you really want to continue", -1);
192 printf ("check aborted.\n");
198 static void sync_disks(NOARGS)
209 static const char *corrupt_msg = "\nThe filesystem superblock is corrupt. "
210 "Try running e2fsck with an alternate\n"
211 "superblock using the -b option. "
212 "(8193 is commonly an alternate superblock;\n"
213 "Hence, 'e2fsck -b 8193 <device>' may recover the filesystem.)\n\n";
215 static void check_super_value(const char *descr, unsigned long value,
216 int flags, unsigned long min, unsigned long max)
218 if (((flags & MIN_CHECK) && (value < min)) ||
219 ((flags & MAX_CHECK) && (value > max))) {
220 printf("Corruption found in superblock. (%s = %lu).\n",
227 static void relocate_hint()
229 static hint_issued = 0;
231 /* Only issue the hint once */
235 printf("Note: if there is several inode or block bitmap blocks\n"
236 "which require relocation, or one part of the inode table\n"
237 "which must be moved, you may wish to try running e2fsck\n"
238 "the '-b 8193' option first. The problem may lie only with\n"
239 "the primary block group descriptor, and the backup block\n"
240 "group descriptor may be OK.\n\n");
245 static void check_super_block(ext2_filsys fs)
247 blk_t first_block, last_block;
248 struct ext2_super_block *s = fs->super;
249 blk_t blocks_per_group = fs->super->s_blocks_per_group;
255 * Verify the super block constants...
257 check_super_value("inodes_count", s->s_inodes_count,
259 check_super_value("blocks_count", s->s_blocks_count,
261 check_super_value("first_data_block", s->s_first_data_block,
262 MAX_CHECK, 0, s->s_blocks_count);
263 check_super_value("log_frag_size", s->s_log_frag_size,
265 check_super_value("log_block_size", s->s_log_block_size,
266 MIN_CHECK | MAX_CHECK, s->s_log_frag_size,
268 check_super_value("frags_per_group", s->s_frags_per_group,
269 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
270 check_super_value("blocks_per_group", s->s_blocks_per_group,
271 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
272 check_super_value("inodes_per_group", s->s_inodes_per_group,
274 check_super_value("r_blocks_count", s->s_r_blocks_count,
275 MAX_CHECK, 0, s->s_blocks_count);
277 retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s),
280 com_err("ext2fs_get_device_size", retval,
281 "while trying to check physical size of filesystem");
284 if (should_be < s->s_blocks_count) {
285 printf("The filesystem size (according to the superblock) is %d blocks\n", s->s_blocks_count);
286 printf("The physical size of the device is %d blocks\n",
288 printf("Either the superblock or the partition table is likely to be corrupt!\n");
294 if (s->s_log_block_size != s->s_log_frag_size) {
295 printf("Superblock block_size = %d, fragsize = %d.\n",
296 EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s));
297 printf("This version of e2fsck does not support fragment "
299 "from the block size.\n");
303 should_be = s->s_frags_per_group /
304 (s->s_log_block_size - s->s_log_frag_size + 1);
305 if (s->s_blocks_per_group != should_be) {
306 printf("Superblock blocks_per_group = %u, should "
307 "have been %u\n", s->s_blocks_per_group,
313 should_be = (s->s_log_block_size == 0) ? 1 : 0;
314 if (s->s_first_data_block != should_be) {
315 printf("Superblock first_data_block = %u, should "
316 "have been %u\n", s->s_first_data_block,
323 * Verify the group descriptors....
325 first_block = fs->super->s_first_data_block;
326 last_block = first_block + blocks_per_group;
328 for (i = 0; i < fs->group_desc_count; i++) {
329 if (i == fs->group_desc_count - 1)
330 last_block = fs->super->s_blocks_count;
331 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
332 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
334 printf("Block bitmap for group %d is not in group. "
336 i, fs->group_desc[i].bg_block_bitmap);
338 if (!ask("Relocate", 1)) {
339 fatal_error("Block bitmap not in group");
341 fs->group_desc[i].bg_block_bitmap = 0;
342 invalid_block_bitmap[i]++;
345 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
346 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
348 printf("Inode bitmap group %d not in group. "
350 i, fs->group_desc[i].bg_inode_bitmap);
352 if (!ask("Relocate", 1)) {
353 fatal_error("Inode bitmap not in group");
355 fs->group_desc[i].bg_inode_bitmap = 0;
356 invalid_inode_bitmap[i]++;
359 if ((fs->group_desc[i].bg_inode_table < first_block) ||
360 ((fs->group_desc[i].bg_inode_table +
361 fs->inode_blocks_per_group - 1) >= last_block)) {
363 printf("Inode table for group %d not in group. "
365 i, fs->group_desc[i].bg_inode_table);
366 printf("WARNING: SEVERE DATA LOSS POSSIBLE.\n");
368 if (!ask("Relocate", 1)) {
369 fatal_error("Inode table not in group");
371 fs->group_desc[i].bg_inode_table = 0;
372 invalid_inode_table[i]++;
375 first_block += fs->super->s_blocks_per_group;
376 last_block += fs->super->s_blocks_per_group;
382 * This routine checks to see if a filesystem can be skipped; if so,
383 * it will exit with E2FSCK_OK. Under some conditions it will print a
384 * message explaining why a check is being forced.
386 static void check_if_skip(ext2_filsys fs)
388 const char *reason = NULL;
390 if (force || bad_blocks_file || cflag)
393 if (fs->super->s_state & EXT2_ERROR_FS)
394 reason = "contains a file system with errors";
395 else if (fs->super->s_mnt_count >=
396 (unsigned) fs->super->s_max_mnt_count)
397 reason = "has reached maximal mount count";
398 else if (fs->super->s_checkinterval &&
399 time(0) >= (fs->super->s_lastcheck +
400 fs->super->s_checkinterval))
401 reason = "has gone too long without being checked";
403 printf("%s %s, check forced.\n", device_name, reason);
406 if (fs->super->s_state & EXT2_VALID_FS) {
407 printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name,
408 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
409 fs->super->s_inodes_count,
410 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
411 fs->super->s_blocks_count);
416 #define PATH_SET "PATH=/sbin"
418 static void PRS(int argc, char *argv[])
423 extern void *mallwatch;
425 char *oldpath = getenv("PATH");
427 /* Update our PATH to include /sbin */
431 newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
433 fatal_error("Couldn't malloc() newpath");
434 strcpy (newpath, PATH_SET);
435 strcat (newpath, ":");
436 strcat (newpath, oldpath);
441 setbuf(stdout, NULL);
442 setbuf(stderr, NULL);
443 initialize_ext2_error_table();
446 program_name = *argv;
447 while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:")) != EOF)
469 /* What we do by default, anyway! */
472 superblock = atoi(optarg);
475 blocksize = atoi(optarg);
478 inode_buffer_blocks = atoi(optarg);
481 process_inode_size = atoi(optarg);
484 replace_bad_blocks++;
486 bad_blocks_file = malloc(strlen(optarg)+1);
487 if (!bad_blocks_file)
488 fatal_error("Couldn't malloc bad_blocks_file");
489 strcpy(bad_blocks_file, optarg);
501 fatal_error ("-F not supported");
508 show_version_only = 1;
512 mallwatch = (void *) strtol(optarg, NULL, 0);
516 device_name = optarg;
521 if (show_version_only)
523 if (optind != argc - 1)
525 if (nflag && !bad_blocks_file && !cflag)
527 filesystem_name = argv[optind];
528 if (device_name == 0)
529 device_name = filesystem_name;
532 int fd = open(filesystem_name, O_RDONLY, 0);
535 com_err("open", errno, "while opening %s for flushing",
539 if (ioctl(fd, BLKFLSBUF, 0) < 0) {
540 com_err("BLKFLSBUF", errno, "while trying to flush %s",
546 fatal_error ("BLKFLSBUF not supported");
547 #endif /* BLKFLSBUF */
551 int main (int argc, char *argv[])
553 errcode_t retval = 0;
554 int exit_value = FSCK_OK;
565 init_resource_track(&global_rtrack);
570 fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
571 E2FSPROGS_VERSION, E2FSPROGS_DATE,
572 EXT2FS_VERSION, EXT2FS_DATE);
574 if (show_version_only)
579 if (!preen && !nflag && !yflag) {
580 if (!isatty (0) || !isatty (1))
581 die ("need terminal for interactive repairs");
585 if (superblock && blocksize) {
586 retval = ext2fs_open(filesystem_name,
587 rwflag ? EXT2_FLAG_RW : 0,
588 superblock, blocksize, unix_io_manager,
590 } else if (superblock) {
591 for (i=0; possible_block_sizes[i]; i++) {
592 retval = ext2fs_open(filesystem_name,
593 rwflag ? EXT2_FLAG_RW : 0,
595 possible_block_sizes[i],
596 unix_io_manager, &fs);
601 retval = ext2fs_open(filesystem_name,
602 rwflag ? EXT2_FLAG_RW : 0,
603 0, 0, unix_io_manager, &fs);
605 com_err(program_name, retval, "while trying to open %s",
608 case EXT2_ET_REV_TOO_HIGH:
609 printf ("Get a newer version of e2fsck!\n");
611 case EXT2_ET_SHORT_READ:
612 printf ("Could this be a zero-length partition?\n");
616 printf("You must have %s access to the "
617 "filesystem or be root\n",
618 rwflag ? "r/w" : "r/o");
621 printf("Possibly non-existent or swap device?\n");
629 #ifdef EXT2_CURRENT_REV
630 if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
631 com_err(program_name, EXT2_ET_REV_TOO_HIGH,
632 "while trying to open %s",
634 printf ("Get a newer version of e2fsck!\n");
639 * If the user specified a specific superblock, presumably the
640 * master superblock has been trashed. So we mark the
641 * superblock as dirty, so it can be written out.
643 if (superblock && rwflag)
644 ext2fs_mark_super_dirty(fs);
646 ehandler_init(fs->io);
648 invalid_inode_bitmap = allocate_memory(sizeof(int) *
649 fs->group_desc_count,
650 "invalid_inode_bitmap");
651 invalid_block_bitmap = allocate_memory(sizeof(int) *
652 fs->group_desc_count,
653 "invalid_block_bitmap");
654 invalid_inode_table = allocate_memory(sizeof(int) *
655 fs->group_desc_count,
656 "invalid_inode_table");
658 check_super_block(fs);
661 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
666 * Mark the system as valid, 'til proven otherwise
668 ext2fs_mark_valid(fs);
671 free(invalid_inode_bitmap);
672 free(invalid_block_bitmap);
673 free(invalid_inode_table);
674 if (restart_e2fsck) {
676 printf("Restarting e2fsck from the beginning...\n");
686 mtrace_print("Cleanup");
688 if (ext2fs_test_changed(fs)) {
689 exit_value = FSCK_NONDESTRUCT;
691 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
693 if (root_filesystem && !read_only_root) {
694 printf("%s: ***** REBOOT LINUX *****\n", device_name);
695 exit_value = FSCK_REBOOT;
698 if (!ext2fs_test_valid(fs))
699 exit_value = FSCK_UNCORRECTED;
701 if (ext2fs_test_valid(fs))
702 fs->super->s_state = EXT2_VALID_FS;
704 fs->super->s_state &= ~EXT2_VALID_FS;
705 fs->super->s_mnt_count = 0;
706 fs->super->s_lastcheck = time(NULL);
707 ext2fs_mark_super_dirty(fs);
716 print_resource_track(&global_rtrack);