Whamcloud - gitweb
e2fsck: add support for expanding the inode size
[tools/e2fsprogs.git] / e2fsck / problem.c
index a713f1b..25df7ed 100644 (file)
@@ -9,6 +9,7 @@
  * %End-Header%
  */
 
+#include "config.h"
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
@@ -353,7 +354,7 @@ static struct e2fsck_problem problem_table[] = {
 
        /* group descriptor N checksum is invalid. */
        { PR_0_GDT_CSUM,
-         N_("@g descriptor %g checksum is invalid.  "),
+         N_("@g descriptor %g checksum is %04x, should be %04y.  "),
             PROMPT_FIX, PR_LATCH_BG_CHECKSUM },
 
        /* group descriptor N marked uninitialized without feature set. */
@@ -361,11 +362,6 @@ static struct e2fsck_problem problem_table[] = {
          N_("@g descriptor %g marked uninitialized without feature set.\n"),
             PROMPT_FIX, PR_PREEN_OK },
 
-       /* group N block bitmap uninitialized but inode bitmap in use. */
-       { PR_0_BB_UNINIT_IB_INIT,
-         N_("@g %g @b @B uninitialized but @i @B in use.\n"),
-            PROMPT_FIX, PR_PREEN_OK },
-
        /* Group descriptor N has invalid unused inodes count. */
        { PR_0_GDT_ITABLE_UNUSED,
          N_("@g descriptor %g has invalid unused inodes count %b.  "),
@@ -402,6 +398,54 @@ static struct e2fsck_problem problem_table[] = {
          N_("One or more @b @g descriptor checksums are invalid.  "),
             PROMPT_FIX, PR_PREEN_OK },
 
+       /* Free inodes count wrong */
+       { PR_0_FREE_INODE_COUNT,
+         N_("Setting free @is count to %j (was %i)\n"),
+         PROMPT_NONE, PR_PREEN_NOMSG },
+
+       /* Free blocks count wrong */
+       { PR_0_FREE_BLOCK_COUNT,
+         N_("Setting free @bs count to %c (was %b)\n"),
+         PROMPT_NONE, PR_PREEN_NOMSG },
+
+       /* Making quota file hidden */
+       { PR_0_HIDE_QUOTA,
+         N_("Making @q @i %i (%Q) hidden.\n"),
+         PROMPT_NONE, PR_PREEN_OK },
+
+       /* Superblock has invalid MMP block. */
+       { PR_0_MMP_INVALID_BLK,
+         N_("@S has invalid MMP block.  "),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
+       /* Superblock has invalid MMP magic. */
+       { PR_0_MMP_INVALID_MAGIC,
+         N_("@S has invalid MMP magic.  "),
+         PROMPT_FIX, PR_PREEN_OK | PR_NO_OK},
+
+       /* Opening file system failed */
+       { PR_0_OPEN_FAILED,
+         N_("ext2fs_open2: %m\n"),
+         PROMPT_NONE, 0 },
+
+       /* Checking group descriptor failed */
+       { PR_0_CHECK_DESC_FAILED,
+         N_("ext2fs_check_desc: %m\n"),
+         PROMPT_NONE, 0 },
+
+       { PR_0_MIN_EXTRA_ISIZE_INVALID,
+         N_("@S has invalid s_min_extra_isize.  "),
+         PROMPT_FIX, PR_PREEN_OK },
+
+       { PR_0_WANT_EXTRA_ISIZE_INVALID,
+         N_("@S has invalid s_want_extra_isize.  "),
+         PROMPT_FIX, PR_PREEN_OK },
+
+       { PR_0_CLEAR_EXTRA_ISIZE,
+         N_("Disable extra_isize feature since @f has 128 byte inodes.\n"),
+         PROMPT_NONE, 0 },
+
+
        /* Pass 1 errors */
 
        /* Pass 1: Checking inodes, blocks, and sizes */
@@ -703,7 +747,7 @@ static struct e2fsck_problem problem_table[] = {
        /* Error reading Extended Attribute block while fixing refcount */
        { PR_1_EXTATTR_READ_ABORT,
          N_("Error reading @a @b %b (%m).  "),
-         PROMPT_ABORT, 0 },
+         PROMPT_NONE, PR_FATAL },
 
        /* Extended attribute reference count incorrect */
        { PR_1_EXTATTR_REFCOUNT,
@@ -711,9 +755,9 @@ static struct e2fsck_problem problem_table[] = {
          PROMPT_FIX, 0 },
 
        /* Error writing Extended Attribute block while fixing refcount */
-       { PR_1_EXTATTR_WRITE,
+       { PR_1_EXTATTR_WRITE_ABORT,
          N_("Error writing @a @b %b (%m).  "),
-         PROMPT_ABORT, 0 },
+         PROMPT_NONE, PR_FATAL },
 
        /* Multiple EA blocks not supported */
        { PR_1_EA_MULTI_BLOCK,
@@ -721,9 +765,9 @@ static struct e2fsck_problem problem_table[] = {
          PROMPT_CLEAR, 0},
 
        /* Error allocating EA region allocation structure */
-       { PR_1_EA_ALLOC_REGION,
+       { PR_1_EA_ALLOC_REGION_ABORT,
          N_("@A @a @b %b.  "),
-         PROMPT_ABORT, 0},
+         PROMPT_NONE, PR_FATAL},
 
        /* Error EA allocation collision */
        { PR_1_EA_ALLOC_COLLISION,
@@ -798,7 +842,7 @@ static struct e2fsck_problem problem_table[] = {
        /* Resize inode failed */
        { PR_1_RESIZE_INODE_CREATE,
          N_("Resize @i (re)creation failed: %m."),
-         PROMPT_ABORT, 0 },
+         PROMPT_CONTINUE, 0 },
 
        /* invalid inode->i_extra_isize */
        { PR_1_EXTRA_ISIZE,
@@ -885,6 +929,73 @@ static struct e2fsck_problem problem_table[] = {
          N_("@i %i has an invalid extent node (blk %b, lblk %c)\n"),
          PROMPT_CLEAR, 0 },
 
+       /* Failed to convert subcluster bitmap */
+       { PR_1_CONVERT_SUBCLUSTER,
+         N_("Error converting subcluster @b @B: %m\n"),
+         PROMPT_NONE, PR_FATAL },
+
+       /* Quota inode has bad mode */
+       { PR_1_QUOTA_BAD_MODE,
+         N_("@q @i is not regular file.  "),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
+       /* Quota inode is not in use, but contains data */
+       { PR_1_QUOTA_INODE_NOT_CLEAR,
+         N_("@q @i is not in use, but contains data.  "),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
+       /* Quota inode is user visible */
+       { PR_1_QUOTA_INODE_NOT_HIDDEN,
+         N_("@q @i is visible to the user.  "),
+         PROMPT_CLEAR, PR_PREEN_OK },
+
+       /* Invalid bad inode */
+       { PR_1_INVALID_BAD_INODE,
+         N_("The bad @b @i looks @n.  "),
+         PROMPT_CLEAR, 0 },
+
+       /* Extent has zero length */
+       { PR_1_EXTENT_LENGTH_ZERO,
+         N_("@i %i has zero length extent\n\t(@n logical @b %c, physical @b %b)\n"),
+         PROMPT_CLEAR, 0 },
+
+       /* Bad extended attribute value in inode */
+       { PR_1_INODE_EA_BAD_VALUE,
+         N_("@a in @i %i is corrupt (@n value)."),
+         PROMPT_CLEAR, 0},
+
+       /* expand inode */
+       { PR_1_EXPAND_EISIZE_WARNING,
+         N_("\ne2fsck is being run with \"expand_extra_isize\" option or\n"
+            "s_min_extra_isize of %d bytes has been set in the superblock.\n"
+            "Inode %i does not have enough free space.  Either some EAs\n"
+            "need to be deleted from this inode or the RO_COMPAT_EXTRA_ISIZE\n"
+            "flag must be cleared.\n\n"), PROMPT_NONE, PR_PREEN_OK | PR_NO_OK |
+            PR_PREEN_NOMSG },
+
+       /* expand inode */
+       { PR_1_EXPAND_EISIZE,
+         N_("Expanding @i %i.\n"),
+         PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_PREEN_NOMSG },
+
+       /* delete an EA so that EXTRA_ISIZE feature may be enabled */
+       { PR_1_EISIZE_DELETE_EA,
+         N_("Delete EA %s of @i %i so that EXTRA_ISIZE feature may be "
+            "enabled?\n"), PROMPT_FIX, PR_NO_OK | PR_PREEN_NO },
+
+       /* an EA needs to be deleted by e2fsck is being run with -p or -y */
+       { PR_1_EA_BLK_NOSPC,
+         N_("An EA needs to be deleted for @i %i but e2fsck is being run\n"
+            "with -p or -y mode.\n"),
+         PROMPT_ABORT, 0 },
+
+       /* disable EXTRA_ISIZE feature since inode cannot be expanded */
+       { PR_1_CLEAR_EXTRA_ISIZE,
+         N_("Disable EXTRA_ISIZE feature since @i %i cannot be expanded\n"
+            "without deletion of an EA.\n"),
+         PROMPT_FIX, 0 },
+
+
        /* Pass 1b errors */
 
        /* Pass 1B: Rescan for duplicate/bad blocks */
@@ -928,7 +1039,6 @@ static struct e2fsck_problem problem_table[] = {
          N_("Error adjusting refcount for @a @b %b (@i %i): %m\n"),
          PROMPT_NONE, 0 },
 
-
        /* Pass 1C: Scan directories for inodes with multiply-claimed blocks. */
        { PR_1C_PASS_HEADER,
          N_("Pass 1C: Scanning directories for @is with @m @bs\n"),
@@ -978,6 +1088,14 @@ static struct e2fsck_problem problem_table[] = {
        { PR_1D_CLONE_ERROR,
          N_("Couldn't clone file: %m\n"), PROMPT_NONE, 0 },
 
+       /* File with shared blocks found */
+       { PR_1D_DISCONNECT_QUESTION,
+         N_("File with shared blocks found\n"), PROMPT_CONNECT, 0 },
+
+       /* Couldn't unlink file (error) */
+       { PR_1D_DISCONNECT_ERROR,
+         N_("Couldn't unlink file: %m\n"), PROMPT_NONE, 0 },
+
        /* Pass 2 errors */
 
        /* Pass 2: Checking directory structure */
@@ -1561,7 +1679,7 @@ static struct e2fsck_problem problem_table[] = {
        /* Free inodes count wrong */
        { PR_5_FREE_INODE_COUNT,
          N_("Free @is count wrong (%i, counted=%j).\n"),
-         PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
+         PROMPT_FIX, PR_PREEN_OK | PR_NO_OK | PR_PREEN_NOMSG },
 
        /* Free blocks count for group wrong */
        { PR_5_FREE_BLOCK_COUNT_GROUP,
@@ -1571,7 +1689,7 @@ static struct e2fsck_problem problem_table[] = {
        /* Free blocks count wrong */
        { PR_5_FREE_BLOCK_COUNT,
          N_("Free @bs count wrong (%b, counted=%c).\n"),
-         PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
+         PROMPT_FIX, PR_PREEN_OK | PR_NO_OK | PR_PREEN_NOMSG },
 
        /* Programming error: bitmap endpoints don't match */
        { PR_5_BMAP_ENDPOINTS,
@@ -1624,6 +1742,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("@g %g @i(s) in use but @g is marked INODE_UNINIT\n"),
          PROMPT_FIX, PR_PREEN_OK },
 
+       /* Expand inode */
+       { PR_5_EXPAND_EISIZE,
+         N_("Expanding @i %i.\n"),
+         PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_PREEN_NOMSG },
+
        /* Post-Pass 5 errors */
 
        /* Recreate journal if E2F_FLAG_JOURNAL_INODE flag is set */
@@ -1631,6 +1754,11 @@ static struct e2fsck_problem problem_table[] = {
          N_("Recreate @j"),
          PROMPT_NULL, PR_PREEN_OK | PR_NO_OK },
 
+       /* Update quota information if it is inconsistent */
+       { PR_6_UPDATE_QUOTAS,
+         N_("Update quota info for quota type %N"),
+         PROMPT_NULL, PR_PREEN_OK | PR_NO_OK },
+
        { 0 }
 };
 
@@ -1768,10 +1896,17 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
                reconfigure_bool(ctx, ptr, key, PR_NOCOLLATE, "no_collate");
                reconfigure_bool(ctx, ptr, key, PR_NO_NOMSG, "no_nomsg");
                reconfigure_bool(ctx, ptr, key, PR_PREEN_NOHDR, "preen_noheader");
+               reconfigure_bool(ctx, ptr, key, PR_FORCE_NO, "force_no");
+               profile_get_integer(ctx->profile, "options",
+                                   "max_count_problems", 0, 0,
+                                   &ptr->max_count);
+               profile_get_integer(ctx->profile, "problems", key, "max_count",
+                                   ptr->max_count, &ptr->max_count);
 
                ptr->flags |= PR_CONFIG;
        }
        def_yn = 1;
+       ptr->count++;
        if ((ptr->flags & PR_NO_DEFAULT) ||
            ((ptr->flags & PR_PREEN_NO) && (ctx->options & E2F_OPT_PREEN)) ||
            (ctx->options & E2F_OPT_NO))
@@ -1798,18 +1933,37 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
            (ctx->options & E2F_OPT_PREEN))
                suppress++;
        if ((ptr->flags & PR_NO_NOMSG) &&
-           (ctx->options & E2F_OPT_NO))
+           ((ctx->options & E2F_OPT_NO) || (ptr->flags & PR_FORCE_NO)))
                suppress++;
+       if (ptr->max_count && (ptr->count > ptr->max_count)) {
+               if (ctx->options & (E2F_OPT_NO | E2F_OPT_YES))
+                       suppress++;
+               if ((ctx->options & E2F_OPT_PREEN) &&
+                   (ptr->flags & PR_PREEN_OK))
+                       suppress++;
+               if ((ptr->flags & PR_LATCH_MASK) &&
+                   (ldesc->flags & (PRL_YES | PRL_NO)))
+                       suppress++;
+               if (ptr->count == ptr->max_count + 1) {
+                       printf("...problem 0x%06x suppressed\n",
+                              ptr->e2p_code);
+                       fflush(stdout);
+               }
+       }
+       message = ptr->e2p_description;
+       if (*message)
+               message = _(message);
        if (!suppress) {
-               message = ptr->e2p_description;
                if ((ctx->options & E2F_OPT_PREEN) &&
                    !(ptr->flags & PR_PREEN_NOHDR)) {
                        printf("%s: ", ctx->device_name ?
                               ctx->device_name : ctx->filesystem_name);
                }
                if (*message)
-                       print_e2fsck_message(ctx, _(message), pctx, 1, 0);
+                       print_e2fsck_message(stdout, ctx, message, pctx, 1, 0);
        }
+       if (ctx->logf && message)
+               print_e2fsck_message(ctx->logf, ctx, message, pctx, 1, 0);
        if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
                preenhalt(ctx);
 
@@ -1822,14 +1976,16 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
                else
                        answer = def_yn;
        } else {
-               if (ctx->options & E2F_OPT_PREEN) {
+               if (ptr->flags & PR_FORCE_NO) {
+                       answer = 0;
+                       print_answer = 1;
+               } else if (ctx->options & E2F_OPT_PREEN) {
                        answer = def_yn;
                        if (!(ptr->flags & PR_PREEN_NOMSG))
                                print_answer = 1;
                } else if ((ptr->flags & PR_LATCH_MASK) &&
                           (ldesc->flags & (PRL_YES | PRL_NO))) {
-                       if (!suppress)
-                               print_answer = 1;
+                       print_answer = 1;
                        if (ldesc->flags & PRL_YES)
                                answer = 1;
                        else
@@ -1840,10 +1996,16 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
                if (!answer && !(ptr->flags & PR_NO_OK))
                        ext2fs_unmark_valid(fs);
 
-               if (print_answer)
-                       printf("%s.\n", answer ?
-                              _(preen_msg[(int) ptr->prompt]) : _("IGNORED"));
-
+               if (print_answer) {
+                       if (!suppress)
+                               printf("%s.\n", answer ?
+                                      _(preen_msg[(int) ptr->prompt]) :
+                                      _("IGNORED"));
+                       if (ctx->logf)
+                               fprintf(ctx->logf, "%s.\n", answer ?
+                                       _(preen_msg[(int) ptr->prompt]) :
+                                       _("IGNORED"));
+               }
        }
 
        if ((ptr->prompt == PROMPT_ABORT) && answer)
@@ -1867,7 +2029,14 @@ profile_get_boolean(profile_t profile, const char *name, const char *subname,
        return 0;
 }
 
-void print_e2fsck_message(e2fsck_t ctx, const char *msg,
+errcode_t
+profile_get_integer(profile_t profile, const char *name, const char *subname,
+                   const char *subsubname, int def_val, int *ret_int)
+{
+       return 0;
+}
+
+void print_e2fsck_message(FILE *f, e2fsck_t ctx, const char *msg,
                          struct problem_context *pctx, int first,
                          int recurse)
 {
@@ -1933,6 +2102,7 @@ int main(int argc, char *argv[])
        e2fsck_t ctx;
        int rc;
 
+       memset(&ctx, 0, sizeof(ctx)); /* just to quiet compiler */
        rc = verify_problem_table(ctx);
        if (rc == 0)
                printf("e2fsck problem table verified\n");