Whamcloud - gitweb
Make e2fsck uninit block group aware
[tools/e2fsprogs.git] / e2fsck / unix.c
index 3d91049..7b662e4 100644 (file)
@@ -258,6 +258,7 @@ static void check_if_skip(e2fsck_t ctx)
        long next_check;
        int batt = is_on_batt();
        int defer_check_on_battery;
+       time_t lastcheck;
 
        profile_get_boolean(ctx->profile, "options",
                            "defer_check_on_battery", 0, 1, 
@@ -268,11 +269,16 @@ static void check_if_skip(e2fsck_t ctx)
        if ((ctx->options & E2F_OPT_FORCE) || bad_blocks_file || cflag)
                return;
        
+       lastcheck = fs->super->s_lastcheck;
+       if (lastcheck > ctx->now)
+               lastcheck -= ctx->time_fudge;
        if ((fs->super->s_state & EXT2_ERROR_FS) ||
            !ext2fs_test_valid(fs))
                reason = _(" contains a file system with errors");
        else if ((fs->super->s_state & EXT2_VALID_FS) == 0)
                reason = _(" was not cleanly unmounted");
+       else if (check_backup_super_block(ctx))
+               reason = _(" primary superblock features different from backup");
        else if ((fs->super->s_max_mnt_count > 0) &&
                 (fs->super->s_mnt_count >=
                  (unsigned) fs->super->s_max_mnt_count)) {
@@ -282,8 +288,7 @@ static void check_if_skip(e2fsck_t ctx)
                             (unsigned) fs->super->s_max_mnt_count*2))
                        reason = 0;
        } else if (fs->super->s_checkinterval &&
-                  ((ctx->now - fs->super->s_lastcheck) >= 
-                   fs->super->s_checkinterval)) {
+                  ((ctx->now - lastcheck) >= fs->super->s_checkinterval)) {
                reason = _(" has gone %u days without being checked");
                reason_arg = (ctx->now - fs->super->s_lastcheck)/(3600*24);
                if (batt && ((ctx->now - fs->super->s_lastcheck) < 
@@ -553,7 +558,9 @@ static void parse_extended_opts(e2fsck_t ctx, const char *opts)
                       "and may take an argument which\n"
                       "is set off by an equals ('=') sign.  "
                        "Valid extended options are:\n"
-                      "\tea_ver=<ea_version (1 or 2)>\n\n"), stderr);
+                       "\tea_ver=<ea_version (1 or 2)>\n"
+                       "\tuninit_groups\n"
+                       "\tinit_groups\n\n"), stderr);
                exit(1);
        }
 }
@@ -582,6 +589,10 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
 #endif
        char            *extended_opts = 0;
        char            *cp;
+       int             res;            /* result of sscanf */
+#ifdef CONFIG_JBD_DEBUG
+       char            *jbd_debug;
+#endif
 
        retval = e2fsck_allocate_context(&ctx);
        if (retval)
@@ -611,7 +622,10 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
                switch (c) {
                case 'C':
                        ctx->progress = e2fsck_update_progress;
-                       ctx->progress_fd = atoi(optarg);
+                       res = sscanf(optarg, "%d", &ctx->progress_fd);
+                       if (res != 1)
+                               goto sscanf_err;
+
                        if (!ctx->progress_fd)
                                break;
                        /* Validate the file descriptor to avoid disasters */
@@ -671,20 +685,26 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
                        /* What we do by default, anyway! */
                        break;
                case 'b':
-                       ctx->use_superblock = atoi(optarg);
+                       res = sscanf(optarg, "%d", &ctx->use_superblock);
+                       if (res != 1)
+                               goto sscanf_err;
                        ctx->flags |= E2F_FLAG_SB_SPECIFIED;
                        break;
                case 'B':
                        ctx->blocksize = atoi(optarg);
                        break;
                case 'I':
-                       ctx->inode_buffer_blocks = atoi(optarg);
+                       res = sscanf(optarg, "%d", &ctx->inode_buffer_blocks);
+                       if (res != 1)
+                               goto sscanf_err;
                        break;
                case 'j':
                        ctx->journal_name = string_copy(ctx, optarg, 0);
                        break;
                case 'P':
-                       ctx->process_inode_size = atoi(optarg);
+                       res = sscanf(optarg, "%d", &ctx->process_inode_size);
+                       if (res != 1)
+                               goto sscanf_err;
                        break;
                case 'L':
                        replace_bad_blocks++;
@@ -727,6 +747,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
        if ((ctx->options & E2F_OPT_NO) && !bad_blocks_file &&
            !cflag && !(ctx->options & E2F_OPT_COMPRESS_DIRS))
                ctx->options |= E2F_OPT_READONLY;
+
        ctx->io_options = strchr(argv[optind], '?');
        if (ctx->io_options) 
                *ctx->io_options++ = 0;
@@ -804,18 +825,31 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
                putenv(newpath);
        }
 #ifdef CONFIG_JBD_DEBUG
-       if (getenv("E2FSCK_JBD_DEBUG"))
-               journal_enable_debug = atoi(getenv("E2FSCK_JBD_DEBUG"));
+       jbd_debug = getenv("E2FSCK_JBD_DEBUG");
+       if (jbd_debug) {
+               res = sscanf(jbd_debug, "%d", &journal_enable_debug);
+               if (res != 1) {
+                       fprintf(stderr,
+                               _("E2FSCK_JBD_DEBUG \"%s\" not an integer\n\n"),
+                               jbd_debug);
+                       exit (1);
+               }
+       }
 #endif
        return 0;
+
+sscanf_err:
+       fprintf(stderr, _("\nInvalid non-numeric argument to -%c (\"%s\")\n\n"),
+               c, optarg);
+       exit (1);
 }
 
 static const char *my_ver_string = E2FSPROGS_VERSION;
 static const char *my_ver_date = E2FSPROGS_DATE;
-                                       
+
 int main (int argc, char *argv[])
 {
-       errcode_t       retval = 0;
+       errcode_t       retval = 0, orig_retval = 0;
        int             exit_value = FSCK_OK;
        ext2_filsys     fs = 0;
        io_manager      io_ptr;
@@ -827,6 +861,7 @@ int main (int argc, char *argv[])
        int flags, run_result;
        int journal_size;
        int sysval, sys_page_size = 4096;
+       __u32 features[3];
        
        clear_problem_context(&pctx);
 #ifdef MTRACE
@@ -888,7 +923,7 @@ restart:
 #else
        io_ptr = unix_io_manager;
 #endif
-       flags = 0;
+       flags = EXT2_FLAG_NOFREE_ON_ERROR;
        if ((ctx->options & E2F_OPT_READONLY) == 0)
                flags |= EXT2_FLAG_RW;
        if ((ctx->mount_flags & EXT2_MF_MOUNTED) == 0)
@@ -915,18 +950,40 @@ restart:
        if (!ctx->superblock && !(ctx->options & E2F_OPT_PREEN) &&
            !(ctx->flags & E2F_FLAG_SB_SPECIFIED) &&
            ((retval == EXT2_ET_BAD_MAGIC) ||
+            (retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
             ((retval == 0) && ext2fs_check_desc(fs)))) {
+               if (fs->flags & EXT2_FLAG_NOFREE_ON_ERROR) {
+                       ext2fs_free(fs);
+                       fs = NULL;
+               }
                if (!fs || (fs->group_desc_count > 1)) {
-                       printf(_("%s trying backup blocks...\n"),
-                              retval ? _("Couldn't find ext2 superblock,") :
+                       printf(_("%s: %s trying backup blocks...\n"),
+                              ctx->program_name, 
+                              retval ? _("Superblock invalid,") :
                               _("Group descriptors look bad..."));
                        get_backup_sb(ctx, fs, ctx->filesystem_name, io_ptr);
                        if (fs)
                                ext2fs_close(fs);
+                       orig_retval = retval;
                        goto restart;
                }
        }
+       if (((retval == EXT2_ET_UNSUPP_FEATURE) ||
+            (retval == EXT2_ET_RO_UNSUPP_FEATURE)) &&
+           fs && fs->super) {
+               sb = fs->super;
+               features[0] = (sb->s_feature_compat & 
+                              ~EXT2_LIB_FEATURE_COMPAT_SUPP);
+               features[1] = (sb->s_feature_incompat & 
+                              ~EXT2_LIB_FEATURE_INCOMPAT_SUPP);
+               features[2] = (sb->s_feature_ro_compat & 
+                              ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP);
+               if (features[0] || features[1] || features[2])
+                       goto print_unsupp_features;
+       }
        if (retval) {
+               if (orig_retval)
+                       retval = orig_retval;
                com_err(ctx->program_name, retval, _("while trying to open %s"),
                        ctx->filesystem_name);
                if (retval == EXT2_ET_REV_TOO_HIGH) {
@@ -1079,15 +1136,26 @@ restart:
         * Check for compatibility with the feature sets.  We need to
         * be more stringent than ext2fs_open().
         */
-       if ((sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP) ||
-           (sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP)) {
-               com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
-                       "(%s)", ctx->device_name);
-               goto get_newer;
-       }
-       if (sb->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
-               com_err(ctx->program_name, EXT2_ET_RO_UNSUPP_FEATURE,
-                       "(%s)", ctx->device_name);
+       features[0] = sb->s_feature_compat & ~EXT2_LIB_FEATURE_COMPAT_SUPP;
+       features[1] = sb->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP;
+       features[2] = (sb->s_feature_ro_compat & 
+                      ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP);
+print_unsupp_features:
+       if (features[0] || features[1] || features[2]) {
+               int     i, j;
+               __u32   *mask = features, m;
+
+               fprintf(stderr, _("%s has unsupported feature(s):"), 
+                       ctx->filesystem_name);
+
+               for (i=0; i <3; i++,mask++) {
+                       for (j=0,m=1; j < 32; j++, m<<=1) {
+                               if (*mask & m)
+                                       fprintf(stderr, " %s", 
+                                               e2p_feature2string(i, m));
+                       }
+               }
+               putc('\n', stderr);
                goto get_newer;
        }
 #ifdef ENABLE_COMPRESSION
@@ -1178,6 +1246,7 @@ restart:
                        if (journal_size < 0) {
                                fs->super->s_feature_compat &=
                                        ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+                               fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
                                com_err(ctx->program_name, 0, 
                                        _("Couldn't determine journal size"));
                                goto no_journal;
@@ -1217,6 +1286,10 @@ no_journal:
        }
        if (run_result & E2F_FLAG_ABORT)
                fatal_error(ctx, _("aborted"));
+       if (check_backup_super_block(ctx)) {
+               fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
+               ext2fs_mark_super_dirty(fs);
+       }
 
 #ifdef MTRACE
        mtrace_print("Cleanup");
@@ -1266,6 +1339,10 @@ no_journal:
                }
        }
 
+       if (sb->s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_GDT_CSUM &&
+           !(ctx->options & E2F_OPT_READONLY))
+               ext2fs_set_gdt_csum(ctx->fs);
+
        e2fsck_write_bitmaps(ctx);
 #ifdef RESOURCE_TRACK
        io_channel_flush(ctx->fs->io);