]> 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
f3db3566
TT
219#define MIN_CHECK 1
220#define MAX_CHECK 2
221
1e3472c5
TT
222static const char *corrupt_msg =
223"\nThe superblock could not be read or does not describe a correct ext2\n"
224"filesystem. If the device is valid and it really contains an ext2\n"
225"filesystem (and not swap or ufs or something else), then the superblock\n"
226"is corrupt, and you might try running e2fsck with an alternate superblock:\n"
227" e2fsck -b 8193 <device>\n\n";
f3db3566
TT
228
229static void check_super_value(const char *descr, unsigned long value,
230 int flags, unsigned long min, unsigned long max)
231{
232 if (((flags & MIN_CHECK) && (value < min)) ||
233 ((flags & MAX_CHECK) && (value > max))) {
234 printf("Corruption found in superblock. (%s = %lu).\n",
235 descr, value);
236 printf(corrupt_msg);
237 fatal_error(0);
238 }
239}
240
1e3472c5 241static void relocate_hint(void)
62c06f79
TT
242{
243 static hint_issued = 0;
244
21c84b71
TT
245 /*
246 * Only issue the hint once, and only if we're using the
247 * primary superblocks.
248 */
249 if (hint_issued || superblock)
62c06f79
TT
250 return;
251
252 printf("Note: if there is several inode or block bitmap blocks\n"
253 "which require relocation, or one part of the inode table\n"
254 "which must be moved, you may wish to try running e2fsck\n"
255 "the '-b 8193' option first. The problem may lie only with\n"
256 "the primary block group descriptor, and the backup block\n"
257 "group descriptor may be OK.\n\n");
258 hint_issued = 1;
259}
260
261
3839e657
TT
262static void check_super_block(ext2_filsys fs)
263{
264 blk_t first_block, last_block;
1e3472c5 265 struct ext2fs_sb *s = (struct ext2fs_sb *) fs->super;
f3db3566 266 blk_t blocks_per_group = fs->super->s_blocks_per_group;
3839e657 267 int i;
f3db3566 268 blk_t should_be;
50e1e10f 269 errcode_t retval;
21c84b71
TT
270 struct problem_context pctx;
271
272 clear_problem_context(&pctx);
3839e657 273
f3db3566
TT
274 /*
275 * Verify the super block constants...
276 */
277 check_super_value("inodes_count", s->s_inodes_count,
278 MIN_CHECK, 1, 0);
279 check_super_value("blocks_count", s->s_blocks_count,
280 MIN_CHECK, 1, 0);
281 check_super_value("first_data_block", s->s_first_data_block,
282 MAX_CHECK, 0, s->s_blocks_count);
283 check_super_value("log_frag_size", s->s_log_frag_size,
284 MAX_CHECK, 0, 2);
285 check_super_value("log_block_size", s->s_log_block_size,
286 MIN_CHECK | MAX_CHECK, s->s_log_frag_size,
287 2);
288 check_super_value("frags_per_group", s->s_frags_per_group,
289 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
290 check_super_value("blocks_per_group", s->s_blocks_per_group,
291 MIN_CHECK | MAX_CHECK, 1, 8 * EXT2_BLOCK_SIZE(s));
292 check_super_value("inodes_per_group", s->s_inodes_per_group,
293 MIN_CHECK, 1, 0);
294 check_super_value("r_blocks_count", s->s_r_blocks_count,
295 MAX_CHECK, 0, s->s_blocks_count);
296
50e1e10f
TT
297 retval = ext2fs_get_device_size(filesystem_name, EXT2_BLOCK_SIZE(s),
298 &should_be);
299 if (retval) {
300 com_err("ext2fs_get_device_size", retval,
301 "while trying to check physical size of filesystem");
302 fatal_error(0);
303 }
304 if (should_be < s->s_blocks_count) {
305 printf("The filesystem size (according to the superblock) is %d blocks\n", s->s_blocks_count);
306 printf("The physical size of the device is %d blocks\n",
307 should_be);
308 printf("Either the superblock or the partition table is likely to be corrupt!\n");
309 preenhalt(fs);
310 if (ask("Abort", 1))
311 fatal_error(0);
312 }
313
f3db3566
TT
314 if (s->s_log_block_size != s->s_log_frag_size) {
315 printf("Superblock block_size = %d, fragsize = %d.\n",
316 EXT2_BLOCK_SIZE(s), EXT2_FRAG_SIZE(s));
317 printf("This version of e2fsck does not support fragment "
318 "sizes different\n"
319 "from the block size.\n");
320 fatal_error(0);
321 }
322
323 should_be = s->s_frags_per_group /
324 (s->s_log_block_size - s->s_log_frag_size + 1);
325 if (s->s_blocks_per_group != should_be) {
50e1e10f
TT
326 printf("Superblock blocks_per_group = %u, should "
327 "have been %u\n", s->s_blocks_per_group,
f3db3566
TT
328 should_be);
329 printf(corrupt_msg);
7f88b043 330 fatal_error(0);
f3db3566
TT
331 }
332
333 should_be = (s->s_log_block_size == 0) ? 1 : 0;
334 if (s->s_first_data_block != should_be) {
50e1e10f
TT
335 printf("Superblock first_data_block = %u, should "
336 "have been %u\n", s->s_first_data_block,
f3db3566
TT
337 should_be);
338 printf(corrupt_msg);
7f88b043 339 fatal_error(0);
f3db3566
TT
340 }
341
342 /*
343 * Verify the group descriptors....
344 */
3839e657
TT
345 first_block = fs->super->s_first_data_block;
346 last_block = first_block + blocks_per_group;
347
348 for (i = 0; i < fs->group_desc_count; i++) {
21c84b71
TT
349 pctx.group = i;
350
f3db3566
TT
351 if (i == fs->group_desc_count - 1)
352 last_block = fs->super->s_blocks_count;
3839e657
TT
353 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
354 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
62c06f79 355 relocate_hint();
21c84b71
TT
356 pctx.blk = fs->group_desc[i].bg_block_bitmap;
357 if (fix_problem(fs, PR_0_BB_NOT_GROUP, &pctx)) {
358 fs->group_desc[i].bg_block_bitmap = 0;
359 invalid_block_bitmap[i]++;
360 invalid_bitmaps++;
f3db3566 361 }
3839e657
TT
362 }
363 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
364 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
62c06f79 365 relocate_hint();
21c84b71
TT
366 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
367 if (fix_problem(fs, PR_0_IB_NOT_GROUP, &pctx)) {
368 fs->group_desc[i].bg_inode_bitmap = 0;
369 invalid_inode_bitmap[i]++;
370 invalid_bitmaps++;
f3db3566 371 }
3839e657
TT
372 }
373 if ((fs->group_desc[i].bg_inode_table < first_block) ||
374 ((fs->group_desc[i].bg_inode_table +
375 fs->inode_blocks_per_group - 1) >= last_block)) {
62c06f79 376 relocate_hint();
21c84b71
TT
377 pctx.blk = fs->group_desc[i].bg_inode_table;
378 if (fix_problem(fs, PR_0_ITABLE_NOT_GROUP, &pctx)) {
379 fs->group_desc[i].bg_inode_table = 0;
380 invalid_inode_table[i]++;
381 invalid_bitmaps++;
f3db3566 382 }
3839e657
TT
383 }
384 first_block += fs->super->s_blocks_per_group;
385 last_block += fs->super->s_blocks_per_group;
386 }
21c84b71
TT
387 /*
388 * If we have invalid bitmaps, set the error state of the
389 * filesystem.
390 */
391 if (invalid_bitmaps && rwflag) {
392 fs->super->s_state &= ~EXT2_VALID_FS;
393 ext2fs_mark_super_dirty(fs);
394 }
1e3472c5
TT
395
396 /*
397 * If the UUID field isn't assigned, assign it.
398 */
399 if (rwflag && uuid_is_null(s->s_uuid)) {
400 if (preen)
401 printf("%s: Adding UUID to filesystem.\n",
402 device_name);
403 else
404 printf("Filesystem did not have a UUID; "
405 "generating one.\n\n");
406 uuid_generate(s->s_uuid);
407 ext2fs_mark_super_dirty(fs);
408 }
3839e657
TT
409 return;
410}
411
412/*
413 * This routine checks to see if a filesystem can be skipped; if so,
414 * it will exit with E2FSCK_OK. Under some conditions it will print a
415 * message explaining why a check is being forced.
416 */
417static void check_if_skip(ext2_filsys fs)
418{
419 const char *reason = NULL;
420
1e3472c5 421 if (force || bad_blocks_file || cflag || swapfs)
3839e657
TT
422 return;
423
424 if (fs->super->s_state & EXT2_ERROR_FS)
425 reason = "contains a file system with errors";
426 else if (fs->super->s_mnt_count >=
427 (unsigned) fs->super->s_max_mnt_count)
428 reason = "has reached maximal mount count";
429 else if (fs->super->s_checkinterval &&
430 time(0) >= (fs->super->s_lastcheck +
431 fs->super->s_checkinterval))
432 reason = "has gone too long without being checked";
5c576477
TT
433 else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
434 reason = "was not cleanly unmounted";
3839e657
TT
435 if (reason) {
436 printf("%s %s, check forced.\n", device_name, reason);
437 return;
438 }
5c576477
TT
439 printf("%s: clean, %d/%d files, %d/%d blocks\n", device_name,
440 fs->super->s_inodes_count - fs->super->s_free_inodes_count,
441 fs->super->s_inodes_count,
442 fs->super->s_blocks_count - fs->super->s_free_blocks_count,
443 fs->super->s_blocks_count);
444 ext2fs_close(fs);
445 exit(FSCK_OK);
3839e657
TT
446}
447
50e1e10f
TT
448#define PATH_SET "PATH=/sbin"
449
3839e657
TT
450static void PRS(int argc, char *argv[])
451{
f3db3566
TT
452 int flush = 0;
453 char c;
3839e657 454#ifdef MTRACE
f3db3566 455 extern void *mallwatch;
3839e657 456#endif
50e1e10f 457 char *oldpath = getenv("PATH");
3839e657
TT
458
459 /* Update our PATH to include /sbin */
50e1e10f
TT
460 if (oldpath) {
461 char *newpath;
462
463 newpath = malloc(sizeof (PATH_SET) + 1 + strlen (oldpath));
464 if (!newpath)
465 fatal_error("Couldn't malloc() newpath");
466 strcpy (newpath, PATH_SET);
467 strcat (newpath, ":");
468 strcat (newpath, oldpath);
469 putenv (newpath);
470 } else
471 putenv (PATH_SET);
3839e657
TT
472
473 setbuf(stdout, NULL);
474 setbuf(stderr, NULL);
475 initialize_ext2_error_table();
476
477 if (argc && *argv)
478 program_name = *argv;
1e3472c5 479 while ((c = getopt (argc, argv, "panyrcB:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF)
3839e657
TT
480 switch (c) {
481 case 'p':
482 case 'a':
483 preen = 1;
484 yflag = nflag = 0;
485 break;
486 case 'n':
487 nflag = 1;
488 preen = yflag = 0;
489 break;
490 case 'y':
491 yflag = 1;
492 preen = nflag = 0;
493 break;
494 case 't':
495 tflag++;
496 break;
497 case 'c':
498 cflag++;
499 break;
500 case 'r':
501 /* What we do by default, anyway! */
502 break;
503 case 'b':
21c84b71 504 use_superblock = atoi(optarg);
3839e657
TT
505 break;
506 case 'B':
507 blocksize = atoi(optarg);
508 break;
509 case 'I':
510 inode_buffer_blocks = atoi(optarg);
511 break;
512 case 'P':
513 process_inode_size = atoi(optarg);
514 break;
515 case 'L':
516 replace_bad_blocks++;
517 case 'l':
518 bad_blocks_file = malloc(strlen(optarg)+1);
519 if (!bad_blocks_file)
520 fatal_error("Couldn't malloc bad_blocks_file");
521 strcpy(bad_blocks_file, optarg);
522 break;
523 case 'd':
524 debug = 1;
525 break;
526 case 'f':
527 force = 1;
528 break;
529 case 'F':
50e1e10f 530#ifdef BLKFLSBUF
3839e657 531 flush = 1;
50e1e10f
TT
532#else
533 fatal_error ("-F not supported");
534#endif
3839e657
TT
535 break;
536 case 'v':
537 verbose = 1;
538 break;
539 case 'V':
540 show_version_only = 1;
541 break;
542#ifdef MTRACE
543 case 'M':
544 mallwatch = (void *) strtol(optarg, NULL, 0);
545 break;
546#endif
50e1e10f
TT
547 case 'N':
548 device_name = optarg;
549 break;
1e3472c5
TT
550 case 's':
551 normalize_swapfs = 1;
552 case 'S':
553 swapfs = 1;
554 break;
3839e657
TT
555 default:
556 usage ();
557 }
558 if (show_version_only)
559 return;
560 if (optind != argc - 1)
561 usage ();
1e3472c5 562 if (nflag && !bad_blocks_file && !cflag && !swapfs)
3839e657 563 rwflag = 0;
50e1e10f
TT
564 filesystem_name = argv[optind];
565 if (device_name == 0)
566 device_name = filesystem_name;
3839e657 567 if (flush) {
50e1e10f
TT
568#ifdef BLKFLSBUF
569 int fd = open(filesystem_name, O_RDONLY, 0);
3839e657
TT
570
571 if (fd < 0) {
572 com_err("open", errno, "while opening %s for flushing",
50e1e10f 573 filesystem_name);
3839e657
TT
574 exit(FSCK_ERROR);
575 }
576 if (ioctl(fd, BLKFLSBUF, 0) < 0) {
577 com_err("BLKFLSBUF", errno, "while trying to flush %s",
50e1e10f 578 filesystem_name);
3839e657
TT
579 exit(FSCK_ERROR);
580 }
581 close(fd);
50e1e10f
TT
582#else
583 fatal_error ("BLKFLSBUF not supported");
584#endif /* BLKFLSBUF */
3839e657 585 }
1e3472c5
TT
586 if (swapfs) {
587 if (cflag || bad_blocks_file) {
588 fprintf(stderr, "Incompatible options not "
589 "allowed when byte-swapping.\n");
590 fatal_error(0);
591 }
592 }
3839e657
TT
593}
594
595int main (int argc, char *argv[])
596{
597 errcode_t retval = 0;
598 int exit_value = FSCK_OK;
599 int i;
21c84b71
TT
600 ext2_filsys fs = 0;
601 io_manager io_ptr;
602 struct ext2fs_sb *s;
3839e657
TT
603
604#ifdef MTRACE
605 mtrace();
606#endif
607#ifdef MCHECK
608 mcheck(0);
609#endif
610
611 init_resource_track(&global_rtrack);
612
613 PRS(argc, argv);
614
21c84b71 615 if (!preen || show_version_only)
3839e657
TT
616 fprintf (stderr, "e2fsck %s, %s for EXT2 FS %s, %s\n",
617 E2FSPROGS_VERSION, E2FSPROGS_DATE,
618 EXT2FS_VERSION, EXT2FS_DATE);
619
5c576477
TT
620 if (show_version_only) {
621 fprintf(stderr, "\tUsing %s\n",
622 error_message(EXT2_ET_BASE));
3839e657 623 exit(0);
5c576477 624 }
3839e657
TT
625
626 check_mount();
627
628 if (!preen && !nflag && !yflag) {
629 if (!isatty (0) || !isatty (1))
630 die ("need terminal for interactive repairs");
631 }
21c84b71 632 superblock = use_superblock;
f3db3566 633restart:
21c84b71
TT
634#if 1
635 io_ptr = unix_io_manager;
636#else
637 io_ptr = test_io_manager;
638 test_io_backing_manager = unix_io_manager;
639#endif
3839e657
TT
640 sync_disks();
641 if (superblock && blocksize) {
50e1e10f
TT
642 retval = ext2fs_open(filesystem_name,
643 rwflag ? EXT2_FLAG_RW : 0,
21c84b71 644 superblock, blocksize, io_ptr, &fs);
3839e657
TT
645 } else if (superblock) {
646 for (i=0; possible_block_sizes[i]; i++) {
50e1e10f 647 retval = ext2fs_open(filesystem_name,
3839e657
TT
648 rwflag ? EXT2_FLAG_RW : 0,
649 superblock,
650 possible_block_sizes[i],
21c84b71 651 io_ptr, &fs);
3839e657
TT
652 if (!retval)
653 break;
654 }
655 } else
50e1e10f
TT
656 retval = ext2fs_open(filesystem_name,
657 rwflag ? EXT2_FLAG_RW : 0,
21c84b71
TT
658 0, 0, io_ptr, &fs);
659 if (!superblock && !preen &&
660 ((retval == EXT2_ET_BAD_MAGIC) ||
661 ((retval == 0) && ext2fs_check_desc(fs)))) {
662 if (!fs || (fs->group_desc_count > 1)) {
663 printf("%s trying backup blocks...\n",
664 retval ? "Couldn't find ext2 superblock," :
665 "Group descriptors look bad...");
666 superblock = 8193;
667 if (fs)
668 ext2fs_close(fs);
669 goto restart;
670 }
671 }
3839e657
TT
672 if (retval) {
673 com_err(program_name, retval, "while trying to open %s",
50e1e10f 674 filesystem_name);
1e3472c5 675 if (retval == EXT2_ET_REV_TOO_HIGH)
f3db3566 676 printf ("Get a newer version of e2fsck!\n");
1e3472c5 677 else if (retval == EXT2_ET_SHORT_READ)
50e1e10f 678 printf ("Could this be a zero-length partition?\n");
1e3472c5 679 else if ((retval == EPERM) || (retval == EACCES))
50e1e10f
TT
680 printf("You must have %s access to the "
681 "filesystem or be root\n",
682 rwflag ? "r/w" : "r/o");
1e3472c5 683 else if (retval == ENXIO)
50e1e10f 684 printf("Possibly non-existent or swap device?\n");
1e3472c5 685 else
f3db3566 686 printf(corrupt_msg);
3839e657
TT
687 fatal_error(0);
688 }
f3db3566
TT
689#ifdef EXT2_CURRENT_REV
690 if (fs->super->s_rev_level > E2FSCK_CURRENT_REV) {
7f88b043
TT
691 com_err(program_name, EXT2_ET_REV_TOO_HIGH,
692 "while trying to open %s",
50e1e10f 693 filesystem_name);
21c84b71
TT
694 goto get_newer;
695 }
696#endif
697 /*
698 * Check for compatibility with the feature sets. We have to
699 * check because we need to be more stringent than ext2fs_open
700 */
701 s = (struct ext2fs_sb *) fs->super;
702 if (s->s_feature_compat || s->s_feature_incompat ||
703 s->s_feature_ro_compat) {
704 com_err(program_name, EXT2_ET_UNSUPP_FEATURE,
705 " (%s)", filesystem_name);
706 get_newer:
f3db3566
TT
707 printf ("Get a newer version of e2fsck!\n");
708 fatal_error(0);
709 }
21c84b71 710
3839e657
TT
711 /*
712 * If the user specified a specific superblock, presumably the
713 * master superblock has been trashed. So we mark the
714 * superblock as dirty, so it can be written out.
715 */
716 if (superblock && rwflag)
717 ext2fs_mark_super_dirty(fs);
718
5c576477
TT
719 /*
720 * Don't overwrite the backup superblock and block
721 * descriptors, until we're sure the filesystem is OK....
722 */
723 fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
724
3839e657
TT
725 ehandler_init(fs->io);
726
f3db3566
TT
727 invalid_inode_bitmap = allocate_memory(sizeof(int) *
728 fs->group_desc_count,
729 "invalid_inode_bitmap");
730 invalid_block_bitmap = allocate_memory(sizeof(int) *
731 fs->group_desc_count,
732 "invalid_block_bitmap");
733 invalid_inode_table = allocate_memory(sizeof(int) *
734 fs->group_desc_count,
735 "invalid_inode_table");
736
3839e657
TT
737 check_super_block(fs);
738 check_if_skip(fs);
739 if (bad_blocks_file)
740 read_bad_blocks_file(fs, bad_blocks_file, replace_bad_blocks);
741 else if (cflag)
742 test_disk(fs);
743
1e3472c5 744 if (normalize_swapfs) {
5c576477
TT
745 if ((fs->flags & EXT2_FLAG_SWAP_BYTES) ==
746 ext2fs_native_flag()) {
1e3472c5
TT
747 fprintf(stderr, "%s: Filesystem byte order "
748 "already normalized.\n", device_name);
749 fatal_error(0);
750 }
751 }
752 if (swapfs)
753 swap_filesys(fs);
754
3839e657
TT
755 /*
756 * Mark the system as valid, 'til proven otherwise
757 */
758 ext2fs_mark_valid(fs);
1e3472c5 759
21c84b71
TT
760 retval = ext2fs_read_bb_inode(fs, &fs->badblocks);
761 if (retval) {
762 com_err(program_name, retval,
763 "while reading bad blocks inode");
764 preenhalt(fs);
765 printf("This doesn't bode well, but we'll try to go on...\n");
766 }
767
3839e657 768 pass1(fs);
50e1e10f
TT
769 free(invalid_inode_bitmap);
770 free(invalid_block_bitmap);
771 free(invalid_inode_table);
f3db3566
TT
772 if (restart_e2fsck) {
773 ext2fs_close(fs);
774 printf("Restarting e2fsck from the beginning...\n");
775 restart_e2fsck = 0;
21c84b71 776 superblock = use_superblock;
f3db3566
TT
777 goto restart;
778 }
3839e657
TT
779 pass2(fs);
780 pass3(fs);
781 pass4(fs);
782 pass5(fs);
783
784#ifdef MTRACE
785 mtrace_print("Cleanup");
786#endif
787 if (ext2fs_test_changed(fs)) {
788 exit_value = FSCK_NONDESTRUCT;
789 if (!preen)
790 printf("\n%s: ***** FILE SYSTEM WAS MODIFIED *****\n",
791 device_name);
792 if (root_filesystem && !read_only_root) {
793 printf("%s: ***** REBOOT LINUX *****\n", device_name);
794 exit_value = FSCK_REBOOT;
795 }
796 }
5c576477
TT
797 if (ext2fs_test_valid(fs))
798 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
799 else
3839e657
TT
800 exit_value = FSCK_UNCORRECTED;
801 if (rwflag) {
1e3472c5
TT
802 if (ext2fs_test_valid(fs)) {
803 if (!(fs->super->s_state & EXT2_VALID_FS))
804 exit_value = FSCK_NONDESTRUCT;
3839e657 805 fs->super->s_state = EXT2_VALID_FS;
1e3472c5 806 } else
3839e657
TT
807 fs->super->s_state &= ~EXT2_VALID_FS;
808 fs->super->s_mnt_count = 0;
809 fs->super->s_lastcheck = time(NULL);
810 ext2fs_mark_super_dirty(fs);
811 }
812 show_stats(fs);
813
814 write_bitmaps(fs);
815 ext2fs_close(fs);
816 sync_disks();
817
818 if (tflag)
819 print_resource_track(&global_rtrack);
820
821 return exit_value;
822}