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 static int show_version_only = 0;
56 static int replace_bad_blocks = 0;
57 static char *bad_blocks_file = 0;
59 static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
61 struct resource_track global_rtrack;
63 static int root_filesystem = 0;
64 static int read_only_root = 0;
66 static void usage(NOARGS)
69 "Usage: %s [-panyrdfvtFV] [-b superblock] [-B blocksize]\n"
70 "\t\tdevice\n", program_name);
74 static void show_stats(ext2_filsys fs)
76 int inodes, inodes_used, blocks, blocks_used;
78 int num_files, num_links;
80 dir_links = 2 * fs_directory_count - 1;
81 num_files = fs_total_count - dir_links;
82 num_links = fs_links_count - dir_links;
83 inodes = fs->super->s_inodes_count;
84 inodes_used = (fs->super->s_inodes_count -
85 fs->super->s_free_inodes_count);
86 blocks = fs->super->s_blocks_count;
87 blocks_used = (fs->super->s_blocks_count -
88 fs->super->s_free_blocks_count);
91 printf("%s: %d/%d files, %d/%d blocks\n", device_name,
92 inodes_used, inodes, blocks_used, blocks);
95 printf ("\n%6d inode%s used (%d%%)\n", inodes_used,
96 (inodes_used != 1) ? "s" : "",
97 100 * inodes_used / inodes);
98 printf ("%6d block%s used (%d%%)\n"
99 "%6d bad block%s\n", blocks_used,
100 (blocks_used != 1) ? "s" : "",
101 100 * blocks_used / blocks, fs_badblocks_count,
102 fs_badblocks_count != 1 ? "s" : "");
103 printf ("\n%6d regular file%s\n"
105 "%6d character device file%s\n"
106 "%6d block device file%s\n"
109 "%6d symbolic link%s (%d fast symbolic link%s)\n"
113 fs_regular_count, (fs_regular_count != 1) ? "s" : "",
114 fs_directory_count, (fs_directory_count != 1) ? "ies" : "y",
115 fs_chardev_count, (fs_chardev_count != 1) ? "s" : "",
116 fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "",
117 fs_fifo_count, (fs_fifo_count != 1) ? "s" : "",
118 fs_links_count - dir_links,
119 ((fs_links_count - dir_links) != 1) ? "s" : "",
120 fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "",
121 fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "",
122 fs_sockets_count, (fs_sockets_count != 1) ? "s" : "",
123 fs_total_count - dir_links,
124 ((fs_total_count - dir_links) != 1) ? "s" : "");
127 static void check_mount(NOARGS)
134 if ((f = setmntent (MOUNTED, "r")) == NULL)
136 while ((mnt = getmntent (f)) != NULL)
137 if (strcmp (device_name, mnt->mnt_fsname) == 0)
143 if (!strcmp(mnt->mnt_dir, "/"))
147 * If the root is mounted read-only, then /etc/mtab is
148 * probably not correct; so we won't issue a warning based on
151 fd = open(MOUNTED, O_RDWR);
153 if (errno == EROFS) {
161 printf("Warning! %s is mounted.\n", device_name);
165 printf ("%s is mounted. ", device_name);
166 if (isatty (0) && isatty (1))
167 cont = ask_yn("Do you really want to continue", -1);
171 printf ("check aborted.\n");
177 static void sync_disks(NOARGS)
185 static void check_super_block(ext2_filsys fs)
187 blk_t first_block, last_block;
188 int blocks_per_group = fs->super->s_blocks_per_group;
191 first_block = fs->super->s_first_data_block;
192 last_block = first_block + blocks_per_group;
194 for (i = 0; i < fs->group_desc_count; i++) {
195 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
196 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
197 printf("Block bitmap %ld for group %d not in group.\n",
198 fs->group_desc[i].bg_block_bitmap, i);
201 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
202 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
203 printf("Inode bitmap %ld for group %d not in group.\n",
204 fs->group_desc[i].bg_inode_bitmap, i);
207 if ((fs->group_desc[i].bg_inode_table < first_block) ||
208 ((fs->group_desc[i].bg_inode_table +
209 fs->inode_blocks_per_group - 1) >= last_block)) {
210 printf("Inode table %ld for group %d not in group.\n",
211 fs->group_desc[i].bg_inode_table, i);
214 first_block += fs->super->s_blocks_per_group;
215 last_block += fs->super->s_blocks_per_group;
221 * This routine checks to see if a filesystem can be skipped; if so,
222 * it will exit with E2FSCK_OK. Under some conditions it will print a
223 * message explaining why a check is being forced.
225 static void check_if_skip(ext2_filsys fs)
227 const char *reason = NULL;
229 if (force || bad_blocks_file || cflag)
232 if (fs->super->s_state & EXT2_ERROR_FS)
233 reason = "contains a file system with errors";
234 else if (fs->super->s_mnt_count >=
235 (unsigned) fs->super->s_max_mnt_count)
236 reason = "has reached maximal mount count";
237 else if (fs->super->s_checkinterval &&
238 time(0) >= (fs->super->s_lastcheck +
239 fs->super->s_checkinterval))
240 reason = "has gone too long without being checked";
242 printf("%s %s, check forced.\n", device_name, reason);
245 if (fs->super->s_state & EXT2_VALID_FS) {
246 printf("%s is clean, no check.\n", device_name);
251 static void PRS(int argc, char *argv[])
256 extern void *mallwatch;
258 char *oldpath, newpath[PATH_MAX];
260 /* Update our PATH to include /sbin */
261 strcpy(newpath, "PATH=/sbin:");
262 if ((oldpath = getenv("PATH")) != NULL)
263 strcat(newpath, oldpath);
266 setbuf(stdout, NULL);
267 setbuf(stderr, NULL);
268 initialize_ext2_error_table();
271 program_name = *argv;
272 while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:")) != EOF)
294 /* What we do by default, anyway! */
297 superblock = atoi(optarg);
300 blocksize = atoi(optarg);
303 inode_buffer_blocks = atoi(optarg);
306 process_inode_size = atoi(optarg);
309 replace_bad_blocks++;
311 bad_blocks_file = malloc(strlen(optarg)+1);
312 if (!bad_blocks_file)
313 fatal_error("Couldn't malloc bad_blocks_file");
314 strcpy(bad_blocks_file, optarg);
329 show_version_only = 1;
333 mallwatch = (void *) strtol(optarg, NULL, 0);
339 if (show_version_only)
341 if (optind != argc - 1)
343 if (nflag && !bad_blocks_file && !cflag)
345 device_name = argv[optind];
347 int fd = open(device_name, O_RDONLY, 0);
350 com_err("open", errno, "while opening %s for flushing",
354 if (ioctl(fd, BLKFLSBUF, 0) < 0) {
355 com_err("BLKFLSBUF", errno, "while trying to flush %s",
363 int main (int argc, char *argv[])
365 errcode_t retval = 0;
366 int exit_value = FSCK_OK;
377 init_resource_track(&global_rtrack);
382 fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
383 E2FSPROGS_VERSION, E2FSPROGS_DATE,
384 EXT2FS_VERSION, EXT2FS_DATE);
386 if (show_version_only)
391 if (!preen && !nflag && !yflag) {
392 if (!isatty (0) || !isatty (1))
393 die ("need terminal for interactive repairs");
396 if (superblock && blocksize) {
397 retval = ext2fs_open(device_name, rwflag ? EXT2_FLAG_RW : 0,
398 superblock, blocksize, unix_io_manager,
400 } else if (superblock) {
401 for (i=0; possible_block_sizes[i]; i++) {
402 retval = ext2fs_open(device_name,
403 rwflag ? EXT2_FLAG_RW : 0,
405 possible_block_sizes[i],
406 unix_io_manager, &fs);
411 retval = ext2fs_open(device_name, rwflag ? EXT2_FLAG_RW : 0,
412 0, 0, unix_io_manager, &fs);
414 com_err(program_name, retval, "while trying to open %s",
416 printf("Couldn't find valid filesystem superblock.\n");
420 * If the user specified a specific superblock, presumably the
421 * master superblock has been trashed. So we mark the
422 * superblock as dirty, so it can be written out.
424 if (superblock && rwflag)
425 ext2fs_mark_super_dirty(fs);
427 ehandler_init(fs->io);
429 check_super_block(fs);
432 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
437 * Mark the system as valid, 'til proven otherwise
439 ext2fs_mark_valid(fs);
448 mtrace_print("Cleanup");
450 if (ext2fs_test_changed(fs)) {
451 exit_value = FSCK_NONDESTRUCT;
453 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
455 if (root_filesystem && !read_only_root) {
456 printf("%s: ***** REBOOT LINUX *****\n", device_name);
457 exit_value = FSCK_REBOOT;
460 if (!ext2fs_test_valid(fs))
461 exit_value = FSCK_UNCORRECTED;
463 if (ext2fs_test_valid(fs))
464 fs->super->s_state = EXT2_VALID_FS;
466 fs->super->s_state &= ~EXT2_VALID_FS;
467 fs->super->s_mnt_count = 0;
468 fs->super->s_lastcheck = time(NULL);
469 ext2fs_mark_super_dirty(fs);
478 print_resource_track(&global_rtrack);