blob: bc9510cb5d7cd0e1582a9d6613903f8798947da2 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * e2fsck.c - a consistency checker for the new extended file system.
3 *
4 * Copyright (C) 1993, 1994 Theodore Ts'o. This file may be
5 * redistributed under the terms of the GNU Public License.
6 */
7
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
15 *
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 :-).
18 */
19
20#include <string.h>
21#include <fcntl.h>
22#include <ctype.h>
23#include <termios.h>
24#include <time.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000025#ifdef HAVE_GETOPT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000026#include <getopt.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000027#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000028#include <unistd.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000029#ifdef HAVE_ERRNO_H
30#include <errno.h>
31#endif
32#ifdef HAVE_MNTENT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000033#include <mntent.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000034#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000035#include <sys/ioctl.h>
36#include <malloc.h>
37
38#include "et/com_err.h"
39#include "e2fsck.h"
40#include "../version.h"
41
42extern int isatty(int);
43
44const char * program_name = "e2fsck";
45const char * device_name = NULL;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000046const char * filesystem_name = NULL;
Theodore Ts'o3839e651997-04-26 13:21:57 +000047
48/* Command line options */
49int nflag = 0;
50int yflag = 0;
51int tflag = 0; /* Do timing */
52int cflag = 0; /* check disk */
53int preen = 0;
54int rwflag = 1;
55int inode_buffer_blocks = 0;
56blk_t superblock;
57int blocksize = 0;
58int verbose = 0;
59int list = 0;
60int debug = 0;
61int force = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +000062int invalid_bitmaps = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +000063static int show_version_only = 0;
64
65static int replace_bad_blocks = 0;
66static char *bad_blocks_file = 0;
67
68static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
69
70struct resource_track global_rtrack;
71
72static int root_filesystem = 0;
73static int read_only_root = 0;
74
Theodore Ts'of3db3561997-04-26 13:34:30 +000075int *invalid_inode_bitmap;
76int *invalid_block_bitmap;
77int *invalid_inode_table;
78int restart_e2fsck = 0;
79
Theodore Ts'o3839e651997-04-26 13:21:57 +000080static void usage(NOARGS)
81{
82 fprintf(stderr,
Theodore Ts'of3db3561997-04-26 13:34:30 +000083 "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);
Theodore Ts'o3839e651997-04-26 13:21:57 +000086 exit(FSCK_USAGE);
87}
88
89static void show_stats(ext2_filsys fs)
90{
91 int inodes, inodes_used, blocks, blocks_used;
92 int dir_links;
93 int num_files, num_links;
94
95 dir_links = 2 * fs_directory_count - 1;
96 num_files = fs_total_count - dir_links;
97 num_links = fs_links_count - dir_links;
98 inodes = fs->super->s_inodes_count;
99 inodes_used = (fs->super->s_inodes_count -
100 fs->super->s_free_inodes_count);
101 blocks = fs->super->s_blocks_count;
102 blocks_used = (fs->super->s_blocks_count -
103 fs->super->s_free_blocks_count);
104
105 if (!verbose) {
106 printf("%s: %d/%d files, %d/%d blocks\n", device_name,
107 inodes_used, inodes, blocks_used, blocks);
108 return;
109 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000110 printf ("\n%8d inode%s used (%d%%)\n", inodes_used,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000111 (inodes_used != 1) ? "s" : "",
112 100 * inodes_used / inodes);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000113 printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n",
114 fs_ind_count, fs_dind_count, fs_tind_count);
115 printf ("%8d block%s used (%d%%)\n"
116 "%8d bad block%s\n", blocks_used,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000117 (blocks_used != 1) ? "s" : "",
118 100 * blocks_used / blocks, fs_badblocks_count,
119 fs_badblocks_count != 1 ? "s" : "");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000120 printf ("\n%8d regular file%s\n"
121 "%8d director%s\n"
122 "%8d character device file%s\n"
123 "%8d block device file%s\n"
124 "%8d fifo%s\n"
125 "%8d link%s\n"
126 "%8d symbolic link%s (%d fast symbolic link%s)\n"
127 "%8d socket%s\n"
128 "--------\n"
129 "%8d file%s\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000130 fs_regular_count, (fs_regular_count != 1) ? "s" : "",
131 fs_directory_count, (fs_directory_count != 1) ? "ies" : "y",
132 fs_chardev_count, (fs_chardev_count != 1) ? "s" : "",
133 fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "",
134 fs_fifo_count, (fs_fifo_count != 1) ? "s" : "",
135 fs_links_count - dir_links,
136 ((fs_links_count - dir_links) != 1) ? "s" : "",
137 fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "",
138 fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "",
139 fs_sockets_count, (fs_sockets_count != 1) ? "s" : "",
140 fs_total_count - dir_links,
141 ((fs_total_count - dir_links) != 1) ? "s" : "");
142}
143
144static void check_mount(NOARGS)
145{
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000146 errcode_t retval;
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000147 int mount_flags, cont, fd;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000148
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000149 retval = ext2fs_check_if_mounted(filesystem_name, &mount_flags);
150 if (retval) {
151 com_err("ext2fs_check_if_mount", retval,
152 "while determining whether %s is mounted.",
153 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000154 return;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000155 }
156 if (!(mount_flags & EXT2_MF_MOUNTED))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000157 return;
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000158
159#if (defined(linux) && defined(HAVE_MNTENT_H))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000160 /*
161 * If the root is mounted read-only, then /etc/mtab is
162 * probably not correct; so we won't issue a warning based on
163 * it.
164 */
Theodore Ts'o297f47a1997-04-26 14:25:20 +0000165 fd = open(MOUNTED, O_RDWR);
166 if (fd < 0) {
167 if (errno == EROFS)
168 return;
169 } else
170 close(fd);
171#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000172
173 if (!rwflag) {
174 printf("Warning! %s is mounted.\n", device_name);
175 return;
176 }
177
178 printf ("%s is mounted. ", device_name);
179 if (isatty (0) && isatty (1))
180 cont = ask_yn("Do you really want to continue", -1);
181 else
182 cont = 0;
183 if (!cont) {
184 printf ("check aborted.\n");
185 exit (0);
186 }
187 return;
188}
189
190static void sync_disks(NOARGS)
191{
192 sync();
193 sync();
194 sleep(1);
195 sync();
196}
197
Theodore Ts'of3db3561997-04-26 13:34:30 +0000198#define MIN_CHECK 1
199#define MAX_CHECK 2
200
201static const char *corrupt_msg = "\nThe filesystem superblock is corrupt. "
202 "Try running e2fsck with an alternate\n"
203 "superblock using the -b option. "
204 "(8193 is commonly an alternate superblock;\n"
205 "Hence, 'e2fsck -b 8193 <device>' may recover the filesystem.)\n\n";
206
207static void check_super_value(const char *descr, unsigned long value,
208 int flags, unsigned long min, unsigned long max)
209{
210 if (((flags & MIN_CHECK) && (value < min)) ||
211 ((flags & MAX_CHECK) && (value > max))) {
212 printf("Corruption found in superblock. (%s = %lu).\n",
213 descr, value);
214 printf(corrupt_msg);
215 fatal_error(0);
216 }
217}
218
Theodore Ts'o3839e651997-04-26 13:21:57 +0000219static void check_super_block(ext2_filsys fs)
220{
221 blk_t first_block, last_block;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000222 struct ext2_super_block *s = fs->super;
223 blk_t blocks_per_group = fs->super->s_blocks_per_group;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000224 int i;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000225 blk_t should_be;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000226 errcode_t retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000227
Theodore Ts'of3db3561997-04-26 13:34:30 +0000228 /*
229 * Verify the super block constants...
230 */
231 check_super_value("inodes_count", s->s_inodes_count,
232 MIN_CHECK, 1, 0);
233 check_super_value("blocks_count", s->s_blocks_count,
234 MIN_CHECK, 1, 0);
235 check_super_value("first_data_block", s->s_first_data_block,
236 MAX_CHECK, 0, s->s_blocks_count);
237 check_super_value("log_frag_size", s->s_log_frag_size,
238 MAX_CHECK, 0, 2);
239 check_super_value("log_block_size", s->s_log_block_size,
240 MIN_CHECK | MAX_CHECK, s->s_log_frag_size,
241 2);
242 check_super_value("frags_per_group", s->s_frags_per_group,
243 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
244 check_super_value("blocks_per_group", s->s_blocks_per_group,
245 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
246 check_super_value("inodes_per_group", s->s_inodes_per_group,
247 MIN_CHECK, 1, 0);
248 check_super_value("r_blocks_count", s->s_r_blocks_count,
249 MAX_CHECK, 0, s->s_blocks_count);
250
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000251 retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s),
252 &should_be);
253 if (retval) {
254 com_err("ext2fs_get_device_size", retval,
255 "while trying to check physical size of filesystem");
256 fatal_error(0);
257 }
258 if (should_be < s->s_blocks_count) {
259 printf("The filesystem size (according to the superblock) is %d blocks\n", s->s_blocks_count);
260 printf("The physical size of the device is %d blocks\n",
261 should_be);
262 printf("Either the superblock or the partition table is likely to be corrupt!\n");
263 preenhalt(fs);
264 if (ask("Abort", 1))
265 fatal_error(0);
266 }
267
Theodore Ts'of3db3561997-04-26 13:34:30 +0000268 if (s->s_log_block_size != s->s_log_frag_size) {
269 printf("Superblock block_size = %d, fragsize = %d.\n",
270 EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s));
271 printf("This version of e2fsck does not support fragment "
272 "sizes different\n"
273 "from the block size.\n");
274 fatal_error(0);
275 }
276
277 should_be = s->s_frags_per_group /
278 (s->s_log_block_size - s->s_log_frag_size + 1);
279 if (s->s_blocks_per_group != should_be) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000280 printf("Superblock blocks_per_group = %u, should "
281 "have been %u\n", s->s_blocks_per_group,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000282 should_be);
283 printf(corrupt_msg);
284 }
285
286 should_be = (s->s_log_block_size == 0) ? 1 : 0;
287 if (s->s_first_data_block != should_be) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000288 printf("Superblock first_data_block = %u, should "
289 "have been %u\n", s->s_first_data_block,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000290 should_be);
291 printf(corrupt_msg);
292 }
293
294 /*
295 * Verify the group descriptors....
296 */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000297 first_block = fs->super->s_first_data_block;
298 last_block = first_block + blocks_per_group;
299
300 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000301 if (i == fs->group_desc_count - 1)
302 last_block = fs->super->s_blocks_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000303 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
304 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000305 printf("Block bitmap for group %d is not in group. "
306 "(block %u)\n",
307 i, fs->group_desc[i].bg_block_bitmap);
308 preenhalt(fs);
309 if (!ask("Relocate", 1)) {
310 fatal_error("Block bitmap not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000311 }
312 fs->group_desc[i].bg_block_bitmap = 0;
313 invalid_block_bitmap[i]++;
314 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000315 }
316 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
317 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000318 printf("Inode bitmap group %d not in group. "
319 "(block %u)\n",
320 i, fs->group_desc[i].bg_inode_bitmap);
321 preenhalt(fs);
322 if (!ask("Relocate", 1)) {
323 fatal_error("Inode bitmap not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000324 }
325 fs->group_desc[i].bg_inode_bitmap = 0;
326 invalid_inode_bitmap[i]++;
327 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000328 }
329 if ((fs->group_desc[i].bg_inode_table < first_block) ||
330 ((fs->group_desc[i].bg_inode_table +
331 fs->inode_blocks_per_group - 1) >= last_block)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000332 printf("Inode table for group %d not in group. "
333 "(block %u)\n",
334 i, fs->group_desc[i].bg_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000335 printf("WARNING: SEVERE DATA LOSS POSSIBLE.\n");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000336 preenhalt(fs);
337 if (!ask("Relocate", 1)) {
338 fatal_error("Inode table not in group");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000339 }
340 fs->group_desc[i].bg_inode_table = 0;
341 invalid_inode_table[i]++;
342 invalid_bitmaps++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000343 }
344 first_block += fs->super->s_blocks_per_group;
345 last_block += fs->super->s_blocks_per_group;
346 }
347 return;
348}
349
350/*
351 * This routine checks to see if a filesystem can be skipped; if so,
352 * it will exit with E2FSCK_OK. Under some conditions it will print a
353 * message explaining why a check is being forced.
354 */
355static void check_if_skip(ext2_filsys fs)
356{
357 const char *reason = NULL;
358
359 if (force || bad_blocks_file || cflag)
360 return;
361
362 if (fs->super->s_state & EXT2_ERROR_FS)
363 reason = "contains a file system with errors";
364 else if (fs->super->s_mnt_count >=
365 (unsigned) fs->super->s_max_mnt_count)
366 reason = "has reached maximal mount count";
367 else if (fs->super->s_checkinterval &&
368 time(0) >= (fs->super->s_lastcheck +
369 fs->super->s_checkinterval))
370 reason = "has gone too long without being checked";
371 if (reason) {
372 printf("%s %s, check forced.\n", device_name, reason);
373 return;
374 }
375 if (fs->super->s_state & EXT2_VALID_FS) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000376 printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name,
377 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
378 fs->super->s_inodes_count,
379 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
380 fs->super->s_blocks_count);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000381 exit(FSCK_OK);
382 }
383}
384
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000385#define PATH_SET "PATH=/sbin"
386
Theodore Ts'o3839e651997-04-26 13:21:57 +0000387static void PRS(int argc, char *argv[])
388{
Theodore Ts'of3db3561997-04-26 13:34:30 +0000389 int flush = 0;
390 char c;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000391#ifdef MTRACE
Theodore Ts'of3db3561997-04-26 13:34:30 +0000392 extern void *mallwatch;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000393#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000394 char *oldpath = getenv("PATH");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000395
396 /* Update our PATH to include /sbin */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000397 if (oldpath) {
398 char *newpath;
399
400 newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
401 if (!newpath)
402 fatal_error("Couldn't malloc() newpath");
403 strcpy (newpath, PATH_SET);
404 strcat (newpath, ":");
405 strcat (newpath, oldpath);
406 putenv (newpath);
407 } else
408 putenv (PATH_SET);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000409
410 setbuf(stdout, NULL);
411 setbuf(stderr, NULL);
412 initialize_ext2_error_table();
413
414 if (argc && *argv)
415 program_name = *argv;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000416 while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:")) != EOF)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000417 switch (c) {
418 case 'p':
419 case 'a':
420 preen = 1;
421 yflag = nflag = 0;
422 break;
423 case 'n':
424 nflag = 1;
425 preen = yflag = 0;
426 break;
427 case 'y':
428 yflag = 1;
429 preen = nflag = 0;
430 break;
431 case 't':
432 tflag++;
433 break;
434 case 'c':
435 cflag++;
436 break;
437 case 'r':
438 /* What we do by default, anyway! */
439 break;
440 case 'b':
441 superblock = atoi(optarg);
442 break;
443 case 'B':
444 blocksize = atoi(optarg);
445 break;
446 case 'I':
447 inode_buffer_blocks = atoi(optarg);
448 break;
449 case 'P':
450 process_inode_size = atoi(optarg);
451 break;
452 case 'L':
453 replace_bad_blocks++;
454 case 'l':
455 bad_blocks_file = malloc(strlen(optarg)+1);
456 if (!bad_blocks_file)
457 fatal_error("Couldn't malloc bad_blocks_file");
458 strcpy(bad_blocks_file, optarg);
459 break;
460 case 'd':
461 debug = 1;
462 break;
463 case 'f':
464 force = 1;
465 break;
466 case 'F':
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000467#ifdef BLKFLSBUF
Theodore Ts'o3839e651997-04-26 13:21:57 +0000468 flush = 1;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000469#else
470 fatal_error ("-F not supported");
471#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000472 break;
473 case 'v':
474 verbose = 1;
475 break;
476 case 'V':
477 show_version_only = 1;
478 break;
479#ifdef MTRACE
480 case 'M':
481 mallwatch = (void *) strtol(optarg, NULL, 0);
482 break;
483#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000484 case 'N':
485 device_name = optarg;
486 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000487 default:
488 usage ();
489 }
490 if (show_version_only)
491 return;
492 if (optind != argc - 1)
493 usage ();
494 if (nflag && !bad_blocks_file && !cflag)
495 rwflag = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000496 filesystem_name = argv[optind];
497 if (device_name == 0)
498 device_name = filesystem_name;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000499 if (flush) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000500#ifdef BLKFLSBUF
501 int fd = open(filesystem_name, O_RDONLY, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000502
503 if (fd < 0) {
504 com_err("open", errno, "while opening %s for flushing",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000505 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000506 exit(FSCK_ERROR);
507 }
508 if (ioctl(fd, BLKFLSBUF, 0) < 0) {
509 com_err("BLKFLSBUF", errno, "while trying to flush %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000510 filesystem_name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000511 exit(FSCK_ERROR);
512 }
513 close(fd);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000514#else
515 fatal_error ("BLKFLSBUF not supported");
516#endif /* BLKFLSBUF */
Theodore Ts'o3839e651997-04-26 13:21:57 +0000517 }
518}
519
520int main (int argc, char *argv[])
521{
522 errcode_t retval = 0;
523 int exit_value = FSCK_OK;
524 int i;
525 ext2_filsys fs;
526
527#ifdef MTRACE
528 mtrace();
529#endif
530#ifdef MCHECK
531 mcheck(0);
532#endif
533
534 init_resource_track(&global_rtrack);
535
536 PRS(argc, argv);
537
538 if (!preen)
539 fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
540 E2FSPROGS_VERSION, E2FSPROGS_DATE,
541 EXT2FS_VERSION, EXT2FS_DATE);
542
543 if (show_version_only)
544 exit(0);
545
546 check_mount();
547
548 if (!preen && !nflag && !yflag) {
549 if (!isatty (0) || !isatty (1))
550 die ("need terminal for interactive repairs");
551 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000552restart:
Theodore Ts'o3839e651997-04-26 13:21:57 +0000553 sync_disks();
554 if (superblock && blocksize) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000555 retval = ext2fs_open(filesystem_name,
556 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000557 superblock, blocksize, unix_io_manager,
558 &fs);
559 } else if (superblock) {
560 for (i=0; possible_block_sizes[i]; i++) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000561 retval = ext2fs_open(filesystem_name,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000562 rwflag ? EXT2_FLAG_RW : 0,
563 superblock,
564 possible_block_sizes[i],
565 unix_io_manager, &fs);
566 if (!retval)
567 break;
568 }
569 } else
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000570 retval = ext2fs_open(filesystem_name,
571 rwflag ? EXT2_FLAG_RW : 0,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000572 0, 0, unix_io_manager, &fs);
573 if (retval) {
574 com_err(program_name, retval, "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000575 filesystem_name);
576 switch (retval) {
577 case EXT2_ET_REV_TOO_HIGH:
Theodore Ts'of3db3561997-04-26 13:34:30 +0000578 printf ("Get a newer version of e2fsck!\n");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000579 break;
580 case EXT2_ET_SHORT_READ:
581 printf ("Could this be a zero-length partition?\n");
582 break;
583 case EPERM:
584 case EACCES:
585 printf("You must have %s access to the "
586 "filesystem or be root\n",
587 rwflag ? "r/w" : "r/o");
588 break;
589 case ENXIO:
590 printf("Possibly non-existent or swap device?\n");
591 break;
592 default:
Theodore Ts'of3db3561997-04-26 13:34:30 +0000593 printf(corrupt_msg);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000594 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000595 fatal_error(0);
596 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000597
598#ifdef EXT2_CURRENT_REV
599 if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
600 com_err(program_name, retval, "while trying to open %s",
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000601 filesystem_name);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000602 printf ("Get a newer version of e2fsck!\n");
603 fatal_error(0);
604 }
605#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000606 /*
607 * If the user specified a specific superblock, presumably the
608 * master superblock has been trashed. So we mark the
609 * superblock as dirty, so it can be written out.
610 */
611 if (superblock && rwflag)
612 ext2fs_mark_super_dirty(fs);
613
614 ehandler_init(fs->io);
615
Theodore Ts'of3db3561997-04-26 13:34:30 +0000616 invalid_inode_bitmap = allocate_memory(sizeof(int) *
617 fs->group_desc_count,
618 "invalid_inode_bitmap");
619 invalid_block_bitmap = allocate_memory(sizeof(int) *
620 fs->group_desc_count,
621 "invalid_block_bitmap");
622 invalid_inode_table = allocate_memory(sizeof(int) *
623 fs->group_desc_count,
624 "invalid_inode_table");
625
Theodore Ts'o3839e651997-04-26 13:21:57 +0000626 check_super_block(fs);
627 check_if_skip(fs);
628 if (bad_blocks_file)
629 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
630 else if (cflag)
631 test_disk(fs);
632
633 /*
634 * Mark the system as valid, 'til proven otherwise
635 */
636 ext2fs_mark_valid(fs);
637
638 pass1(fs);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000639 free(invalid_inode_bitmap);
640 free(invalid_block_bitmap);
641 free(invalid_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000642 if (restart_e2fsck) {
643 ext2fs_close(fs);
644 printf("Restarting e2fsck from the beginning...\n");
645 restart_e2fsck = 0;
646 goto restart;
647 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000648 pass2(fs);
649 pass3(fs);
650 pass4(fs);
651 pass5(fs);
652
653#ifdef MTRACE
654 mtrace_print("Cleanup");
655#endif
656 if (ext2fs_test_changed(fs)) {
657 exit_value = FSCK_NONDESTRUCT;
658 if (!preen)
659 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
660 device_name);
661 if (root_filesystem && !read_only_root) {
662 printf("%s: ***** REBOOT LINUX *****\n", device_name);
663 exit_value = FSCK_REBOOT;
664 }
665 }
666 if (!ext2fs_test_valid(fs))
667 exit_value = FSCK_UNCORRECTED;
668 if (rwflag) {
669 if (ext2fs_test_valid(fs))
670 fs->super->s_state = EXT2_VALID_FS;
671 else
672 fs->super->s_state &= ~EXT2_VALID_FS;
673 fs->super->s_mnt_count = 0;
674 fs->super->s_lastcheck = time(NULL);
675 ext2fs_mark_super_dirty(fs);
676 }
677 show_stats(fs);
678
679 write_bitmaps(fs);
680 ext2fs_close(fs);
681 sync_disks();
682
683 if (tflag)
684 print_resource_track(&global_rtrack);
685
686 return exit_value;
687}