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 :-).
28 #include <sys/ioctl.h>
31 #include "et/com_err.h"
33 #include "../version.h"
35 extern int isatty(int);
37 const char * program_name = "e2fsck";
38 const char * device_name = NULL;
40 /* Command line options */
43 int tflag = 0; /* Do timing */
44 int cflag = 0; /* check disk */
47 int inode_buffer_blocks = 0;
54 int invalid_bitmaps = 0;
55 static int show_version_only = 0;
57 static int replace_bad_blocks = 0;
58 static char *bad_blocks_file = 0;
60 static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
62 struct resource_track global_rtrack;
64 static int root_filesystem = 0;
65 static int read_only_root = 0;
67 int *invalid_inode_bitmap;
68 int *invalid_block_bitmap;
69 int *invalid_inode_table;
70 int restart_e2fsck = 0;
72 static void usage(NOARGS)
75 "Usage: %s [-panyrcdfvtFV] [-b superblock] [-B blocksize]\n"
76 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
77 "\t\t[-l|-L bad_blocks_file] device\n", program_name);
81 static void show_stats(ext2_filsys fs)
83 int inodes, inodes_used, blocks, blocks_used;
85 int num_files, num_links;
87 dir_links = 2 * fs_directory_count - 1;
88 num_files = fs_total_count - dir_links;
89 num_links = fs_links_count - dir_links;
90 inodes = fs->super->s_inodes_count;
91 inodes_used = (fs->super->s_inodes_count -
92 fs->super->s_free_inodes_count);
93 blocks = fs->super->s_blocks_count;
94 blocks_used = (fs->super->s_blocks_count -
95 fs->super->s_free_blocks_count);
98 printf("%s: %d/%d files, %d/%d blocks\n", device_name,
99 inodes_used, inodes, blocks_used, blocks);
102 printf ("\n%6d inode%s used (%d%%)\n", inodes_used,
103 (inodes_used != 1) ? "s" : "",
104 100 * inodes_used / inodes);
105 printf ("%6d block%s used (%d%%)\n"
106 "%6d bad block%s\n", blocks_used,
107 (blocks_used != 1) ? "s" : "",
108 100 * blocks_used / blocks, fs_badblocks_count,
109 fs_badblocks_count != 1 ? "s" : "");
110 printf ("\n%6d regular file%s\n"
112 "%6d character device file%s\n"
113 "%6d block device file%s\n"
116 "%6d symbolic link%s (%d fast symbolic link%s)\n"
120 fs_regular_count, (fs_regular_count != 1) ? "s" : "",
121 fs_directory_count, (fs_directory_count != 1) ? "ies" : "y",
122 fs_chardev_count, (fs_chardev_count != 1) ? "s" : "",
123 fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "",
124 fs_fifo_count, (fs_fifo_count != 1) ? "s" : "",
125 fs_links_count - dir_links,
126 ((fs_links_count - dir_links) != 1) ? "s" : "",
127 fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "",
128 fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "",
129 fs_sockets_count, (fs_sockets_count != 1) ? "s" : "",
130 fs_total_count - dir_links,
131 ((fs_total_count - dir_links) != 1) ? "s" : "");
134 static void check_mount(NOARGS)
141 if ((f = setmntent (MOUNTED, "r")) == NULL)
143 while ((mnt = getmntent (f)) != NULL)
144 if (strcmp (device_name, mnt->mnt_fsname) == 0)
150 if (!strcmp(mnt->mnt_dir, "/"))
154 * If the root is mounted read-only, then /etc/mtab is
155 * probably not correct; so we won't issue a warning based on
158 fd = open(MOUNTED, O_RDWR);
160 if (errno == EROFS) {
168 printf("Warning! %s is mounted.\n", device_name);
172 printf ("%s is mounted. ", device_name);
173 if (isatty (0) && isatty (1))
174 cont = ask_yn("Do you really want to continue", -1);
178 printf ("check aborted.\n");
184 static void sync_disks(NOARGS)
195 static const char *corrupt_msg = "\nThe filesystem superblock is corrupt. "
196 "Try running e2fsck with an alternate\n"
197 "superblock using the -b option. "
198 "(8193 is commonly an alternate superblock;\n"
199 "Hence, 'e2fsck -b 8193 <device>' may recover the filesystem.)\n\n";
201 static void check_super_value(const char *descr, unsigned long value,
202 int flags, unsigned long min, unsigned long max)
204 if (((flags & MIN_CHECK) && (value < min)) ||
205 ((flags & MAX_CHECK) && (value > max))) {
206 printf("Corruption found in superblock. (%s = %lu).\n",
213 static void check_super_block(ext2_filsys fs)
215 blk_t first_block, last_block;
216 struct ext2_super_block *s = fs->super;
217 blk_t blocks_per_group = fs->super->s_blocks_per_group;
222 * Verify the super block constants...
224 check_super_value("inodes_count", s->s_inodes_count,
226 check_super_value("blocks_count", s->s_blocks_count,
228 check_super_value("first_data_block", s->s_first_data_block,
229 MAX_CHECK, 0, s->s_blocks_count);
230 check_super_value("log_frag_size", s->s_log_frag_size,
232 check_super_value("log_block_size", s->s_log_block_size,
233 MIN_CHECK | MAX_CHECK, s->s_log_frag_size,
235 check_super_value("frags_per_group", s->s_frags_per_group,
236 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
237 check_super_value("blocks_per_group", s->s_blocks_per_group,
238 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
239 check_super_value("inodes_per_group", s->s_inodes_per_group,
241 check_super_value("r_blocks_count", s->s_r_blocks_count,
242 MAX_CHECK, 0, s->s_blocks_count);
244 if (s->s_log_block_size != s->s_log_frag_size) {
245 printf("Superblock block_size = %d, fragsize = %d.\n",
246 EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s));
247 printf("This version of e2fsck does not support fragment "
249 "from the block size.\n");
253 should_be = s->s_frags_per_group /
254 (s->s_log_block_size - s->s_log_frag_size + 1);
255 if (s->s_blocks_per_group != should_be) {
256 printf("Superblock blocks_per_group = %lu, should "
257 "have been %lu\n", s->s_blocks_per_group,
262 should_be = (s->s_log_block_size == 0) ? 1 : 0;
263 if (s->s_first_data_block != should_be) {
264 printf("Superblock first_data_block = %lu, should "
265 "have been %lu\n", s->s_first_data_block,
271 * Verify the group descriptors....
273 first_block = fs->super->s_first_data_block;
274 last_block = first_block + blocks_per_group;
276 for (i = 0; i < fs->group_desc_count; i++) {
277 if (i == fs->group_desc_count - 1)
278 last_block = fs->super->s_blocks_count;
279 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
280 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
281 printf("Block bitmap %lu for group %d is "
283 fs->group_desc[i].bg_block_bitmap, i);
285 if (!ask("Continue (and relocate)", 1)) {
288 fs->group_desc[i].bg_block_bitmap = 0;
289 invalid_block_bitmap[i]++;
292 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
293 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
294 printf("Warning: Inode bitmap %lu for group %d "
296 fs->group_desc[i].bg_inode_bitmap, i);
298 if (!ask("Continue", 1)) {
301 fs->group_desc[i].bg_inode_bitmap = 0;
302 invalid_inode_bitmap[i]++;
305 if ((fs->group_desc[i].bg_inode_table < first_block) ||
306 ((fs->group_desc[i].bg_inode_table +
307 fs->inode_blocks_per_group - 1) >= last_block)) {
308 printf("Warning: Inode table %lu for group %d "
310 fs->group_desc[i].bg_inode_table, i);
311 printf("WARNING: SEVERE DATA LOSS POSSIBLE.\n");
313 if (!ask("Continue", 1)) {
316 fs->group_desc[i].bg_inode_table = 0;
317 invalid_inode_table[i]++;
320 first_block += fs->super->s_blocks_per_group;
321 last_block += fs->super->s_blocks_per_group;
327 * This routine checks to see if a filesystem can be skipped; if so,
328 * it will exit with E2FSCK_OK. Under some conditions it will print a
329 * message explaining why a check is being forced.
331 static void check_if_skip(ext2_filsys fs)
333 const char *reason = NULL;
335 if (force || bad_blocks_file || cflag)
338 if (fs->super->s_state & EXT2_ERROR_FS)
339 reason = "contains a file system with errors";
340 else if (fs->super->s_mnt_count >=
341 (unsigned) fs->super->s_max_mnt_count)
342 reason = "has reached maximal mount count";
343 else if (fs->super->s_checkinterval &&
344 time(0) >= (fs->super->s_lastcheck +
345 fs->super->s_checkinterval))
346 reason = "has gone too long without being checked";
348 printf("%s %s, check forced.\n", device_name, reason);
351 if (fs->super->s_state & EXT2_VALID_FS) {
352 printf("%s is clean, no check.\n", device_name);
357 static void PRS(int argc, char *argv[])
362 extern void *mallwatch;
365 static char newpath[PATH_MAX];
367 /* Update our PATH to include /sbin */
368 strcpy(newpath, "PATH=/sbin:");
369 if ((oldpath = getenv("PATH")) != NULL)
370 strcat(newpath, oldpath);
373 setbuf(stdout, NULL);
374 setbuf(stderr, NULL);
375 initialize_ext2_error_table();
378 program_name = *argv;
379 while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:")) != EOF)
401 /* What we do by default, anyway! */
404 superblock = atoi(optarg);
407 blocksize = atoi(optarg);
410 inode_buffer_blocks = atoi(optarg);
413 process_inode_size = atoi(optarg);
416 replace_bad_blocks++;
418 bad_blocks_file = malloc(strlen(optarg)+1);
419 if (!bad_blocks_file)
420 fatal_error("Couldn't malloc bad_blocks_file");
421 strcpy(bad_blocks_file, optarg);
436 show_version_only = 1;
440 mallwatch = (void *) strtol(optarg, NULL, 0);
446 if (show_version_only)
448 if (optind != argc - 1)
450 if (nflag && !bad_blocks_file && !cflag)
452 device_name = argv[optind];
454 int fd = open(device_name, O_RDONLY, 0);
457 com_err("open", errno, "while opening %s for flushing",
461 if (ioctl(fd, BLKFLSBUF, 0) < 0) {
462 com_err("BLKFLSBUF", errno, "while trying to flush %s",
470 int main (int argc, char *argv[])
472 errcode_t retval = 0;
473 int exit_value = FSCK_OK;
484 init_resource_track(&global_rtrack);
489 fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
490 E2FSPROGS_VERSION, E2FSPROGS_DATE,
491 EXT2FS_VERSION, EXT2FS_DATE);
493 if (show_version_only)
498 if (!preen && !nflag && !yflag) {
499 if (!isatty (0) || !isatty (1))
500 die ("need terminal for interactive repairs");
504 if (superblock && blocksize) {
505 retval = ext2fs_open(device_name, rwflag ? EXT2_FLAG_RW : 0,
506 superblock, blocksize, unix_io_manager,
508 } else if (superblock) {
509 for (i=0; possible_block_sizes[i]; i++) {
510 retval = ext2fs_open(device_name,
511 rwflag ? EXT2_FLAG_RW : 0,
513 possible_block_sizes[i],
514 unix_io_manager, &fs);
519 retval = ext2fs_open(device_name, rwflag ? EXT2_FLAG_RW : 0,
520 0, 0, unix_io_manager, &fs);
522 com_err(program_name, retval, "while trying to open %s",
524 if (retval == EXT2_ET_REV_TOO_HIGH)
525 printf ("Get a newer version of e2fsck!\n");
531 #ifdef EXT2_CURRENT_REV
532 if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
533 com_err(program_name, retval, "while trying to open %s",
535 printf ("Get a newer version of e2fsck!\n");
540 * If the user specified a specific superblock, presumably the
541 * master superblock has been trashed. So we mark the
542 * superblock as dirty, so it can be written out.
544 if (superblock && rwflag)
545 ext2fs_mark_super_dirty(fs);
547 ehandler_init(fs->io);
549 invalid_inode_bitmap = allocate_memory(sizeof(int) *
550 fs->group_desc_count,
551 "invalid_inode_bitmap");
552 invalid_block_bitmap = allocate_memory(sizeof(int) *
553 fs->group_desc_count,
554 "invalid_block_bitmap");
555 invalid_inode_table = allocate_memory(sizeof(int) *
556 fs->group_desc_count,
557 "invalid_inode_table");
559 check_super_block(fs);
562 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
567 * Mark the system as valid, 'til proven otherwise
569 ext2fs_mark_valid(fs);
572 if (restart_e2fsck) {
574 printf("Restarting e2fsck from the beginning...\n");
584 mtrace_print("Cleanup");
586 if (ext2fs_test_changed(fs)) {
587 exit_value = FSCK_NONDESTRUCT;
589 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
591 if (root_filesystem && !read_only_root) {
592 printf("%s: ***** REBOOT LINUX *****\n", device_name);
593 exit_value = FSCK_REBOOT;
596 if (!ext2fs_test_valid(fs))
597 exit_value = FSCK_UNCORRECTED;
599 if (ext2fs_test_valid(fs))
600 fs->super->s_state = EXT2_VALID_FS;
602 fs->super->s_state &= ~EXT2_VALID_FS;
603 fs->super->s_mnt_count = 0;
604 fs->super->s_lastcheck = time(NULL);
605 ext2fs_mark_super_dirty(fs);
614 print_resource_track(&global_rtrack);