Whamcloud - gitweb
ChangeLog, error_message.c, error_table.h, et_name.c:
[tools/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 }