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