]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/e2fsck.c
Many files:
[thirdparty/e2fsprogs.git] / e2fsck / e2fsck.c
CommitLineData
3839e657
TT
1/*
2 * e2fsck.c - a consistency checker for the new extended file system.
3 *
21c84b71
TT
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
3839e657
TT
10 */
11
12/* Usage: e2fsck [-dfpnsvy] device
13 * -d -- debugging this program
14 * -f -- check the fs even if it is marked valid
15 * -p -- "preen" the filesystem
16 * -n -- open the filesystem r/o mode; never try to fix problems
17 * -v -- verbose (tells how many files)
18 * -y -- always answer yes to questions
19 *
20 * The device may be a block device or a image of one, but this isn't
21 * enforced (but it's not much fun on a character device :-).
22 */
23
1e3472c5
TT
24#include <stdio.h>
25#ifdef HAVE_STDLIB_H
26#include <stdlib.h>
27#endif
3839e657
TT
28#include <string.h>
29#include <fcntl.h>
30#include <ctype.h>
31#include <termios.h>
32#include <time.h>
50e1e10f 33#ifdef HAVE_GETOPT_H
3839e657 34#include <getopt.h>
50e1e10f 35#endif
3839e657 36#include <unistd.h>
50e1e10f
TT
37#ifdef HAVE_ERRNO_H
38#include <errno.h>
39#endif
40#ifdef HAVE_MNTENT_H
3839e657 41#include <mntent.h>
50e1e10f 42#endif
3839e657
TT
43#include <sys/ioctl.h>
44#include <malloc.h>
45
46#include "et/com_err.h"
1e3472c5 47#include "uuid/uuid.h"
3839e657 48#include "e2fsck.h"
21c84b71 49#include "problem.h"
3839e657
TT
50#include "../version.h"
51
52extern int isatty(int);
53
54const char * program_name = "e2fsck";
55const char * device_name = NULL;
50e1e10f 56const char * filesystem_name = NULL;
3839e657
TT
57
58/* Command line options */
59int nflag = 0;
60int yflag = 0;
61int tflag = 0; /* Do timing */
62int cflag = 0; /* check disk */
63int preen = 0;
64int rwflag = 1;
1e3472c5
TT
65int swapfs = 0;
66int normalize_swapfs = 0;
3839e657 67int inode_buffer_blocks = 0;
21c84b71 68blk_t use_superblock;
3839e657
TT
69blk_t superblock;
70int blocksize = 0;
71int verbose = 0;
72int list = 0;
73int debug = 0;
74int force = 0;
f3db3566 75int invalid_bitmaps = 0;
3839e657
TT
76static int show_version_only = 0;
77
78static int replace_bad_blocks = 0;
79static char *bad_blocks_file = 0;
80
81static int possible_block_sizes[] = { 1024, 2048, 4096, 8192, 0};
82
83struct resource_track global_rtrack;
84
85static int root_filesystem = 0;
86static int read_only_root = 0;
87
f3db3566
TT
88int *invalid_inode_bitmap;
89int *invalid_block_bitmap;
90int *invalid_inode_table;
91int restart_e2fsck = 0;
92
3839e657
TT
93static void usage(NOARGS)
94{
95 fprintf(stderr,
1e3472c5 96 "Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n"
f3db3566
TT
97 "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
98 "\t\t[-l|-L bad_blocks_file] device\n", program_name);
3839e657
TT
99 exit(FSCK_USAGE);
100}
101
102static void show_stats(ext2_filsys fs)
103{
104 int inodes, inodes_used, blocks, blocks_used;
105 int dir_links;
106 int num_files, num_links;
7f88b043 107 int frag_percent;
3839e657
TT
108
109 dir_links = 2 * fs_directory_count - 1;
110 num_files = fs_total_count - dir_links;
111 num_links = fs_links_count - dir_links;
112 inodes = fs->super->s_inodes_count;
113 inodes_used = (fs->super->s_inodes_count -
114 fs->super->s_free_inodes_count);
115 blocks = fs->super->s_blocks_count;
116 blocks_used = (fs->super->s_blocks_count -
117 fs->super->s_free_blocks_count);
7f88b043
TT
118
119 frag_percent = (10000 * fs_fragmented) / inodes_used;
120 frag_percent = (frag_percent + 5) / 10;
3839e657
TT
121
122 if (!verbose) {
7f88b043 123 printf("%s: %d/%d files (%0d.%d%% non-contiguous), %d/%d blocks\n",
74becf3c 124 device_name, inodes_used, inodes,
7f88b043 125 frag_percent / 10, frag_percent % 10,
74becf3c 126 blocks_used, blocks);
3839e657
TT
127 return;
128 }
50e1e10f 129 printf ("\n%8d inode%s used (%d%%)\n", inodes_used,
3839e657
TT
130 (inodes_used != 1) ? "s" : "",
131 100 * inodes_used / inodes);
7f88b043
TT
132 printf ("%8d non-contiguous inodes (%0d.%d%%)\n",
133 fs_fragmented, frag_percent / 10, frag_percent % 10);
50e1e10f
TT
134 printf (" # of inodes with ind/dind/tind blocks: %d/%d/%d\n",
135 fs_ind_count, fs_dind_count, fs_tind_count);
136 printf ("%8d block%s used (%d%%)\n"
137 "%8d bad block%s\n", blocks_used,
3839e657
TT
138 (blocks_used != 1) ? "s" : "",
139 100 * blocks_used / blocks, fs_badblocks_count,
140 fs_badblocks_count != 1 ? "s" : "");
50e1e10f
TT
141 printf ("\n%8d regular file%s\n"
142 "%8d director%s\n"
143 "%8d character device file%s\n"
144 "%8d block device file%s\n"
145 "%8d fifo%s\n"
146 "%8d link%s\n"
147 "%8d symbolic link%s (%d fast symbolic link%s)\n"
148 "%8d socket%s\n"
149 "--------\n"
150 "%8d file%s\n",
3839e657
TT
151 fs_regular_count, (fs_regular_count != 1) ? "s" : "",
152 fs_directory_count, (fs_directory_count != 1) ? "ies" : "y",
153 fs_chardev_count, (fs_chardev_count != 1) ? "s" : "",
154 fs_blockdev_count, (fs_blockdev_count != 1) ? "s" : "",
155 fs_fifo_count, (fs_fifo_count != 1) ? "s" : "",
156 fs_links_count - dir_links,
157 ((fs_links_count - dir_links) != 1) ? "s" : "",
158 fs_symlinks_count, (fs_symlinks_count != 1) ? "s" : "",
159 fs_fast_symlinks_count, (fs_fast_symlinks_count != 1) ? "s" : "",
160 fs_sockets_count, (fs_sockets_count != 1) ? "s" : "",
161 fs_total_count - dir_links,
162 ((fs_total_count - dir_links) != 1) ? "s" : "");
163}
164
165static void check_mount(NOARGS)
166{
50e1e10f 167 errcode_t retval;
297f47a1 168 int mount_flags, cont, fd;
3839e657 169
50e1e10f
TT
170 retval = ext2fs_check_if_mounted(filesystem_name, &mount_flags);
171 if (retval) {
172 com_err("ext2fs_check_if_mount", retval,
173 "while determining whether %s is mounted.",
174 filesystem_name);
3839e657 175 return;
50e1e10f
TT
176 }
177 if (!(mount_flags & EXT2_MF_MOUNTED))
3839e657 178 return;
297f47a1 179
74becf3c 180#if (defined(__linux__) && defined(HAVE_MNTENT_H))
3839e657
TT
181 /*
182 * If the root is mounted read-only, then /etc/mtab is
183 * probably not correct; so we won't issue a warning based on
184 * it.
185 */
297f47a1
TT
186 fd = open(MOUNTED, O_RDWR);
187 if (fd < 0) {
188 if (errno == EROFS)
189 return;
190 } else
191 close(fd);
192#endif
3839e657
TT
193
194 if (!rwflag) {
195 printf("Warning! %s is mounted.\n", device_name);
196 return;
197 }
198
199 printf ("%s is mounted. ", device_name);
200 if (isatty (0) && isatty (1))
201 cont = ask_yn("Do you really want to continue", -1);
202 else
203 cont = 0;
204 if (!cont) {
205 printf ("check aborted.\n");
206 exit (0);
207 }
208 return;
209}
210
211static void sync_disks(NOARGS)
212{
213 sync();
214 sync();
215 sleep(1);
216 sync();
217}
218
521e3685
TT
219static blk_t get_backup_sb(ext2_filsys fs)
220{
221 if (!fs || !fs->super)
222 return 8193;
223 return fs->super->s_blocks_per_group + 1;
224}
225
f3db3566
TT
226#define MIN_CHECK 1
227#define MAX_CHECK 2
228
1e3472c5
TT
229static const char *corrupt_msg =
230"\nThe superblock could not be read or does not describe a correct ext2\n"
231"filesystem. If the device is valid and it really contains an ext2\n"
232"filesystem (and not swap or ufs or something else), then the superblock\n"
233"is corrupt, and you might try running e2fsck with an alternate superblock:\n"
521e3685 234" e2fsck -b %d <device>\n\n";
f3db3566 235
521e3685
TT
236static void check_super_value(ext2_filsys fs, const char *descr,
237 unsigned long value, int flags,
238 unsigned long min, unsigned long max)
f3db3566
TT
239{
240 if (((flags & MIN_CHECK) && (value < min)) ||
241 ((flags & MAX_CHECK) && (value > max))) {
242 printf("Corruption found in superblock. (%s = %lu).\n",
243 descr, value);
521e3685 244 printf(corrupt_msg, get_backup_sb(fs));
f3db3566
TT
245 fatal_error(0);
246 }
247}
248
521e3685 249static void relocate_hint(ext2_filsys fs)
62c06f79
TT
250{
251 static hint_issued = 0;
252
21c84b71
TT
253 /*
254 * Only issue the hint once, and only if we're using the
255 * primary superblocks.
256 */
257 if (hint_issued || superblock)
62c06f79
TT
258 return;
259
260 printf("Note: if there is several inode or block bitmap blocks\n"
261 "which require relocation, or one part of the inode table\n"
262 "which must be moved, you may wish to try running e2fsck\n"
521e3685
TT
263 "with the '-b %d' option first. The problem may lie only\n"
264 "with the primary block group descriptor, and the backup\n"
265 "block group descriptor may be OK.\n\n", get_backup_sb(fs));
62c06f79
TT
266 hint_issued = 1;
267}
268
269
3839e657
TT
270static void check_super_block(ext2_filsys fs)
271{
272 blk_t first_block, last_block;
1e3472c5 273 struct ext2fs_sb *s = (struct ext2fs_sb *) fs->super;
f3db3566 274 blk_t blocks_per_group = fs->super->s_blocks_per_group;
3839e657 275 int i;
f3db3566 276 blk_t should_be;
50e1e10f 277 errcode_t retval;
21c84b71
TT
278 struct problem_context pctx;
279
280 clear_problem_context(&pctx);
3839e657 281
f3db3566
TT
282 /*
283 * Verify the super block constants...
284 */
521e3685 285 check_super_value(fs, "inodes_count", s->s_inodes_count,
f3db3566 286 MIN_CHECK, 1, 0);
521e3685 287 check_super_value(fs, "blocks_count", s->s_blocks_count,
f3db3566 288 MIN_CHECK, 1, 0);
521e3685 289 check_super_value(fs, "first_data_block", s->s_first_data_block,
f3db3566 290 MAX_CHECK, 0, s->s_blocks_count);
521e3685 291 check_super_value(fs, "log_frag_size", s->s_log_frag_size,
f3db3566 292 MAX_CHECK, 0, 2);
521e3685 293 check_super_value(fs, "log_block_size", s->s_log_block_size,
f3db3566
TT
294 MIN_CHECK | MAX_CHECK, s->s_log_frag_size,
295 2);
521e3685 296 check_super_value(fs, "frags_per_group", s->s_frags_per_group,
f3db3566 297 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
521e3685 298 check_super_value(fs, "blocks_per_group", s->s_blocks_per_group,
f3db3566 299 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
521e3685 300 check_super_value(fs, "inodes_per_group", s->s_inodes_per_group,
f3db3566 301 MIN_CHECK, 1, 0);
521e3685 302 check_super_value(fs, "r_blocks_count", s->s_r_blocks_count,
f3db3566
TT
303 MAX_CHECK, 0, s->s_blocks_count);
304
50e1e10f
TT
305 retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s),
306 &should_be);
307 if (retval) {
308 com_err("ext2fs_get_device_size", retval,
309 "while trying to check physical size of filesystem");
310 fatal_error(0);
311 }
312 if (should_be < s->s_blocks_count) {
313 printf("The filesystem size (according to the superblock) is %d blocks\n", s->s_blocks_count);
314 printf("The physical size of the device is %d blocks\n",
315 should_be);
316 printf("Either the superblock or the partition table is likely to be corrupt!\n");
317 preenhalt(fs);
318 if (ask("Abort", 1))
319 fatal_error(0);
320 }
321
f3db3566
TT
322 if (s->s_log_block_size != s->s_log_frag_size) {
323 printf("Superblock block_size = %d, fragsize = %d.\n",
324 EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s));
325 printf("This version of e2fsck does not support fragment "
326 "sizes different\n"
327 "from the block size.\n");
328 fatal_error(0);
329 }
330
331 should_be = s->s_frags_per_group /
332 (s->s_log_block_size - s->s_log_frag_size + 1);
333 if (s->s_blocks_per_group != should_be) {
50e1e10f
TT
334 printf("Superblock blocks_per_group = %u, should "
335 "have been %u\n", s->s_blocks_per_group,
f3db3566 336 should_be);
521e3685 337 printf(corrupt_msg, get_backup_sb(fs));
7f88b043 338 fatal_error(0);
f3db3566
TT
339 }
340
341 should_be = (s->s_log_block_size == 0) ? 1 : 0;
342 if (s->s_first_data_block != should_be) {
50e1e10f
TT
343 printf("Superblock first_data_block = %u, should "
344 "have been %u\n", s->s_first_data_block,
f3db3566 345 should_be);
521e3685 346 printf(corrupt_msg, get_backup_sb(fs));
7f88b043 347 fatal_error(0);
f3db3566
TT
348 }
349
350 /*
351 * Verify the group descriptors....
352 */
3839e657
TT
353 first_block = fs->super->s_first_data_block;
354 last_block = first_block + blocks_per_group;
355
356 for (i = 0; i < fs->group_desc_count; i++) {
21c84b71
TT
357 pctx.group = i;
358
f3db3566
TT
359 if (i == fs->group_desc_count - 1)
360 last_block = fs->super->s_blocks_count;
3839e657
TT
361 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
362 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
521e3685 363 relocate_hint(fs);
21c84b71
TT
364 pctx.blk = fs->group_desc[i].bg_block_bitmap;
365 if (fix_problem(fs, PR_0_BB_NOT_GROUP, &pctx)) {
366 fs->group_desc[i].bg_block_bitmap = 0;
367 invalid_block_bitmap[i]++;
368 invalid_bitmaps++;
f3db3566 369 }
3839e657
TT
370 }
371 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
372 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
521e3685 373 relocate_hint(fs);
21c84b71
TT
374 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
375 if (fix_problem(fs, PR_0_IB_NOT_GROUP, &pctx)) {
376 fs->group_desc[i].bg_inode_bitmap = 0;
377 invalid_inode_bitmap[i]++;
378 invalid_bitmaps++;
f3db3566 379 }
3839e657
TT
380 }
381 if ((fs->group_desc[i].bg_inode_table < first_block) ||
382 ((fs->group_desc[i].bg_inode_table +
383 fs->inode_blocks_per_group - 1) >= last_block)) {
521e3685 384 relocate_hint(fs);
21c84b71
TT
385 pctx.blk = fs->group_desc[i].bg_inode_table;
386 if (fix_problem(fs, PR_0_ITABLE_NOT_GROUP, &pctx)) {
387 fs->group_desc[i].bg_inode_table = 0;
388 invalid_inode_table[i]++;
389 invalid_bitmaps++;
f3db3566 390 }
3839e657
TT
391 }
392 first_block += fs->super->s_blocks_per_group;
393 last_block += fs->super->s_blocks_per_group;
394 }
21c84b71
TT
395 /*
396 * If we have invalid bitmaps, set the error state of the
397 * filesystem.
398 */
399 if (invalid_bitmaps && rwflag) {
400 fs->super->s_state &= ~EXT2_VALID_FS;
401 ext2fs_mark_super_dirty(fs);
402 }
1e3472c5
TT
403
404 /*
405 * If the UUID field isn't assigned, assign it.
406 */
407 if (rwflag && uuid_is_null(s->s_uuid)) {
408 if (preen)
409 printf("%s: Adding UUID to filesystem.\n",
410 device_name);
411 else
412 printf("Filesystem did not have a UUID; "
413 "generating one.\n\n");
414 uuid_generate(s->s_uuid);
415 ext2fs_mark_super_dirty(fs);
416 }
3839e657
TT
417 return;
418}
419
420/*
421 * This routine checks to see if a filesystem can be skipped; if so,
422 * it will exit with E2FSCK_OK. Under some conditions it will print a
423 * message explaining why a check is being forced.
424 */
425static void check_if_skip(ext2_filsys fs)
426{
427 const char *reason = NULL;
428
1e3472c5 429 if (force || bad_blocks_file || cflag || swapfs)
3839e657
TT
430 return;
431
432 if (fs->super->s_state & EXT2_ERROR_FS)
433 reason = "contains a file system with errors";
434 else if (fs->super->s_mnt_count >=
435 (unsigned) fs->super->s_max_mnt_count)
436 reason = "has reached maximal mount count";
437 else if (fs->super->s_checkinterval &&
438 time(0) >= (fs->super->s_lastcheck +
439 fs->super->s_checkinterval))
440 reason = "has gone too long without being checked";
5c576477
TT
441 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
442 reason = "was not cleanly unmounted";
3839e657
TT
443 if (reason) {
444 printf("%s %s, check forced.\n", device_name, reason);
445 return;
446 }
5c576477
TT
447 printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name,
448 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
449 fs->super->s_inodes_count,
450 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
451 fs->super->s_blocks_count);
452 ext2fs_close(fs);
453 exit(FSCK_OK);
3839e657
TT
454}
455
50e1e10f
TT
456#define PATH_SET "PATH=/sbin"
457
3839e657
TT
458static void PRS(int argc, char *argv[])
459{
f3db3566
TT
460 int flush = 0;
461 char c;
3839e657 462#ifdef MTRACE
f3db3566 463 extern void *mallwatch;
3839e657 464#endif
50e1e10f 465 char *oldpath = getenv("PATH");
3839e657
TT
466
467 /* Update our PATH to include /sbin */
50e1e10f
TT
468 if (oldpath) {
469 char *newpath;
470
471 newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
472 if (!newpath)
473 fatal_error("Couldn't malloc() newpath");
474 strcpy (newpath, PATH_SET);
475 strcat (newpath, ":");
476 strcat (newpath, oldpath);
477 putenv (newpath);
478 } else
479 putenv (PATH_SET);
3839e657
TT
480
481 setbuf(stdout, NULL);
482 setbuf(stderr, NULL);
483 initialize_ext2_error_table();
484
485 if (argc && *argv)
486 program_name = *argv;
1e3472c5 487 while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF)
3839e657
TT
488 switch (c) {
489 case 'p':
490 case 'a':
491 preen = 1;
492 yflag = nflag = 0;
493 break;
494 case 'n':
495 nflag = 1;
496 preen = yflag = 0;
497 break;
498 case 'y':
499 yflag = 1;
500 preen = nflag = 0;
501 break;
502 case 't':
503 tflag++;
504 break;
505 case 'c':
506 cflag++;
507 break;
508 case 'r':
509 /* What we do by default, anyway! */
510 break;
511 case 'b':
21c84b71 512 use_superblock = atoi(optarg);
3839e657
TT
513 break;
514 case 'B':
515 blocksize = atoi(optarg);
516 break;
517 case 'I':
518 inode_buffer_blocks = atoi(optarg);
519 break;
520 case 'P':
521 process_inode_size = atoi(optarg);
522 break;
523 case 'L':
524 replace_bad_blocks++;
525 case 'l':
526 bad_blocks_file = malloc(strlen(optarg)+1);
527 if (!bad_blocks_file)
528 fatal_error("Couldn't malloc bad_blocks_file");
529 strcpy(bad_blocks_file, optarg);
530 break;
531 case 'd':
532 debug = 1;
533 break;
534 case 'f':
535 force = 1;
536 break;
537 case 'F':
50e1e10f 538#ifdef BLKFLSBUF
3839e657 539 flush = 1;
50e1e10f
TT
540#else
541 fatal_error ("-F not supported");
542#endif
3839e657
TT
543 break;
544 case 'v':
545 verbose = 1;
546 break;
547 case 'V':
548 show_version_only = 1;
549 break;
550#ifdef MTRACE
551 case 'M':
552 mallwatch = (void *) strtol(optarg, NULL, 0);
553 break;
554#endif
50e1e10f
TT
555 case 'N':
556 device_name = optarg;
557 break;
1e3472c5
TT
558 case 's':
559 normalize_swapfs = 1;
560 case 'S':
561 swapfs = 1;
562 break;
3839e657
TT
563 default:
564 usage ();
565 }
566 if (show_version_only)
567 return;
568 if (optind != argc - 1)
569 usage ();
1e3472c5 570 if (nflag && !bad_blocks_file && !cflag && !swapfs)
3839e657 571 rwflag = 0;
50e1e10f
TT
572 filesystem_name = argv[optind];
573 if (device_name == 0)
574 device_name = filesystem_name;
3839e657 575 if (flush) {
50e1e10f
TT
576#ifdef BLKFLSBUF
577 int fd = open(filesystem_name, O_RDONLY, 0);
3839e657
TT
578
579 if (fd < 0) {
580 com_err("open", errno, "while opening %s for flushing",
50e1e10f 581 filesystem_name);
3839e657
TT
582 exit(FSCK_ERROR);
583 }
584 if (ioctl(fd, BLKFLSBUF, 0) < 0) {
585 com_err("BLKFLSBUF", errno, "while trying to flush %s",
50e1e10f 586 filesystem_name);
3839e657
TT
587 exit(FSCK_ERROR);
588 }
589 close(fd);
50e1e10f
TT
590#else
591 fatal_error ("BLKFLSBUF not supported");
592#endif /* BLKFLSBUF */
3839e657 593 }
1e3472c5
TT
594 if (swapfs) {
595 if (cflag || bad_blocks_file) {
596 fprintf(stderr, "Incompatible options not "
597 "allowed when byte-swapping.\n");
598 fatal_error(0);
599 }
600 }
3839e657 601}
521e3685
TT
602
603static const char *my_ver_string = E2FSPROGS_VERSION;
604static const char *my_ver_date = E2FSPROGS_DATE;
3839e657
TT
605
606int main (int argc, char *argv[])
607{
608 errcode_t retval = 0;
609 int exit_value = FSCK_OK;
610 int i;
21c84b71
TT
611 ext2_filsys fs = 0;
612 io_manager io_ptr;
613 struct ext2fs_sb *s;
521e3685
TT
614 const char *lib_ver_date;
615 int my_ver, lib_ver;
3839e657
TT
616
617#ifdef MTRACE
618 mtrace();
619#endif
620#ifdef MCHECK
621 mcheck(0);
622#endif
521e3685
TT
623 my_ver = ext2fs_parse_version_string(my_ver_string);
624 lib_ver = ext2fs_get_library_version(0, &lib_ver_date);
625 if (my_ver > lib_ver) {
626 fprintf( stderr, "Error: ext2fs library version "
627 "out of date!\n");
628 show_version_only++;
629 }
3839e657
TT
630
631 init_resource_track(&global_rtrack);
632
633 PRS(argc, argv);
634
21c84b71 635 if (!preen || show_version_only)
3839e657 636 fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
521e3685
TT
637 my_ver_string, my_ver_date, EXT2FS_VERSION,
638 EXT2FS_DATE);
3839e657 639
5c576477 640 if (show_version_only) {
521e3685
TT
641 fprintf(stderr, "\tUsing %s, %s\n",
642 error_message(EXT2_ET_BASE), lib_ver_date);
3839e657 643 exit(0);
5c576477 644 }
3839e657
TT
645
646 check_mount();
647
648 if (!preen && !nflag && !yflag) {
649 if (!isatty (0) || !isatty (1))
650 die ("need terminal for interactive repairs");
651 }
21c84b71 652 superblock = use_superblock;
f3db3566 653restart:
21c84b71
TT
654#if 1
655 io_ptr = unix_io_manager;
656#else
657 io_ptr = test_io_manager;
658 test_io_backing_manager = unix_io_manager;
659#endif
3839e657
TT
660 sync_disks();
661 if (superblock && blocksize) {
50e1e10f
TT
662 retval = ext2fs_open(filesystem_name,
663 rwflag ? EXT2_FLAG_RW : 0,
21c84b71 664 superblock, blocksize, io_ptr, &fs);
3839e657
TT
665 } else if (superblock) {
666 for (i=0; possible_block_sizes[i]; i++) {
50e1e10f 667 retval = ext2fs_open(filesystem_name,
3839e657
TT
668 rwflag ? EXT2_FLAG_RW : 0,
669 superblock,
670 possible_block_sizes[i],
21c84b71 671 io_ptr, &fs);
3839e657
TT
672 if (!retval)
673 break;
674 }
675 } else
50e1e10f
TT
676 retval = ext2fs_open(filesystem_name,
677 rwflag ? EXT2_FLAG_RW : 0,
21c84b71
TT
678 0, 0, io_ptr, &fs);
679 if (!superblock && !preen &&
680 ((retval == EXT2_ET_BAD_MAGIC) ||
681 ((retval == 0) && ext2fs_check_desc(fs)))) {
682 if (!fs || (fs->group_desc_count > 1)) {
683 printf("%s trying backup blocks...\n",
684 retval ? "Couldn't find ext2 superblock," :
685 "Group descriptors look bad...");
521e3685 686 superblock = get_backup_sb(fs);
21c84b71
TT
687 if (fs)
688 ext2fs_close(fs);
689 goto restart;
690 }
691 }
3839e657
TT
692 if (retval) {
693 com_err(program_name, retval, "while trying to open %s",
50e1e10f 694 filesystem_name);
1e3472c5 695 if (retval == EXT2_ET_REV_TOO_HIGH)
f3db3566 696 printf ("Get a newer version of e2fsck!\n");
1e3472c5 697 else if (retval == EXT2_ET_SHORT_READ)
50e1e10f 698 printf ("Could this be a zero-length partition?\n");
1e3472c5 699 else if ((retval == EPERM) || (retval == EACCES))
50e1e10f
TT
700 printf("You must have %s access to the "
701 "filesystem or be root\n",
702 rwflag ? "r/w" : "r/o");
1e3472c5 703 else if (retval == ENXIO)
50e1e10f 704 printf("Possibly non-existent or swap device?\n");
1e3472c5 705 else
521e3685 706 printf(corrupt_msg, get_backup_sb(fs));
3839e657
TT
707 fatal_error(0);
708 }
f3db3566
TT
709#ifdef EXT2_CURRENT_REV
710 if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
7f88b043
TT
711 com_err(program_name, EXT2_ET_REV_TOO_HIGH,
712 "while trying to open %s",
50e1e10f 713 filesystem_name);
21c84b71
TT
714 goto get_newer;
715 }
716#endif
717 /*
521e3685
TT
718 * Check for compatibility with the feature sets. We need to
719 * be more stringent than ext2fs_open().
21c84b71
TT
720 */
721 s = (struct ext2fs_sb *) fs->super;
521e3685
TT
722 if ((s->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
723 (s->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
21c84b71 724 com_err(program_name, EXT2_ET_UNSUPP_FEATURE,
521e3685 725 "(%s)", filesystem_name);
21c84b71 726 get_newer:
f3db3566
TT
727 printf ("Get a newer version of e2fsck!\n");
728 fatal_error(0);
729 }
521e3685
TT
730 if (s->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
731 com_err(program_name, EXT2_ET_RO_UNSUPP_FEATURE,
732 "(%s)", filesystem_name);
733 goto get_newer;
734 }
21c84b71 735
3839e657
TT
736 /*
737 * If the user specified a specific superblock, presumably the
738 * master superblock has been trashed. So we mark the
739 * superblock as dirty, so it can be written out.
740 */
741 if (superblock && rwflag)
742 ext2fs_mark_super_dirty(fs);
743
5c576477
TT
744 /*
745 * Don't overwrite the backup superblock and block
746 * descriptors, until we're sure the filesystem is OK....
747 */
748 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
749
3839e657
TT
750 ehandler_init(fs->io);
751
f3db3566
TT
752 invalid_inode_bitmap = allocate_memory(sizeof(int) *
753 fs->group_desc_count,
754 "invalid_inode_bitmap");
755 invalid_block_bitmap = allocate_memory(sizeof(int) *
756 fs->group_desc_count,
757 "invalid_block_bitmap");
758 invalid_inode_table = allocate_memory(sizeof(int) *
759 fs->group_desc_count,
760 "invalid_inode_table");
761
3839e657
TT
762 check_super_block(fs);
763 check_if_skip(fs);
764 if (bad_blocks_file)
765 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
766 else if (cflag)
767 test_disk(fs);
768
1e3472c5 769 if (normalize_swapfs) {
5c576477
TT
770 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ==
771 ext2fs_native_flag()) {
1e3472c5
TT
772 fprintf(stderr, "%s: Filesystem byte order "
773 "already normalized.\n", device_name);
774 fatal_error(0);
775 }
776 }
777 if (swapfs)
778 swap_filesys(fs);
779
3839e657
TT
780 /*
781 * Mark the system as valid, 'til proven otherwise
782 */
783 ext2fs_mark_valid(fs);
1e3472c5 784
21c84b71
TT
785 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
786 if (retval) {
787 com_err(program_name, retval,
788 "while reading bad blocks inode");
789 preenhalt(fs);
790 printf("This doesn't bode well, but we'll try to go on...\n");
791 }
792
3839e657 793 pass1(fs);
50e1e10f
TT
794 free(invalid_inode_bitmap);
795 free(invalid_block_bitmap);
796 free(invalid_inode_table);
f3db3566
TT
797 if (restart_e2fsck) {
798 ext2fs_close(fs);
799 printf("Restarting e2fsck from the beginning...\n");
800 restart_e2fsck = 0;
21c84b71 801 superblock = use_superblock;
f3db3566
TT
802 goto restart;
803 }
3839e657
TT
804 pass2(fs);
805 pass3(fs);
806 pass4(fs);
807 pass5(fs);
808
809#ifdef MTRACE
810 mtrace_print("Cleanup");
811#endif
812 if (ext2fs_test_changed(fs)) {
813 exit_value = FSCK_NONDESTRUCT;
814 if (!preen)
815 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
816 device_name);
817 if (root_filesystem && !read_only_root) {
818 printf("%s: ***** REBOOT LINUX *****\n", device_name);
819 exit_value = FSCK_REBOOT;
820 }
821 }
5c576477
TT
822 if (ext2fs_test_valid(fs))
823 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
824 else
3839e657
TT
825 exit_value = FSCK_UNCORRECTED;
826 if (rwflag) {
1e3472c5
TT
827 if (ext2fs_test_valid(fs)) {
828 if (!(fs->super->s_state & EXT2_VALID_FS))
829 exit_value = FSCK_NONDESTRUCT;
3839e657 830 fs->super->s_state = EXT2_VALID_FS;
1e3472c5 831 } else
3839e657
TT
832 fs->super->s_state &= ~EXT2_VALID_FS;
833 fs->super->s_mnt_count = 0;
834 fs->super->s_lastcheck = time(NULL);
835 ext2fs_mark_super_dirty(fs);
836 }
837 show_stats(fs);
838
839 write_bitmaps(fs);
840 ext2fs_close(fs);
841 sync_disks();
842
843 if (tflag)
844 print_resource_track(&global_rtrack);
845
846 return exit_value;
847}