2 * problem.c --- report filesystem problems to the user
4 * Copyright 1996, 1997 by Theodore Ts'o
7 * This file may be redistributed under the terms of the GNU Public
23 #define PROMPT_CLEAR 1
24 #define PROMPT_RELOCATE 2
25 #define PROMPT_ALLOCATE 3
26 #define PROMPT_EXPAND 4
27 #define PROMPT_CONNECT 5
28 #define PROMPT_CREATE 6
29 #define PROMPT_SALVAGE 7
30 #define PROMPT_TRUNCATE 8
31 #define PROMPT_CLEAR_INODE 9
34 * These are the prompts which are used to ask the user if they want
37 static const char *prompt[] = {
43 "Connect to /lost+found", /* 5 */
51 * These messages are printed when we are preen mode and we will be
52 * automatically fixing the problem.
54 static const char *preen_msg[] = {
60 "RECONNECTED", /* 5 */
64 "INODE CLEARED" /* 9 */
67 static struct e2fsck_problem problem_table[] = {
69 /* Pre-Pass 1 errors */
71 /* Block bitmap not in group */
72 { PR_0_BB_NOT_GROUP, "@b @B for @g %g is not in @g. (@b %b)\n",
75 /* Inode bitmap not in group */
76 { PR_0_IB_NOT_GROUP, "@i @B for @g %g is not in @g. (@b %b)\n",
79 /* Inode table not in group */
80 { PR_0_ITABLE_NOT_GROUP,
81 "@i table for @g %g is not in @g. (@b %b)\n"
82 "WARNING: SEVERE DATA LOSS POSSIBLE.\n",
87 /* Root directory is not an inode */
88 { PR_1_ROOT_NO_DIR, "@r is not a @d. ",
91 /* Root directory has dtime set */
93 "@r has dtime set (probably due to old mke2fs). ",
94 PROMPT_FIX, PR_PREEN_OK },
96 /* Reserved inode has bad mode */
97 { PR_1_RESERVED_BAD_MODE,
98 "Reserved @i %i has bad mode. ",
99 PROMPT_CLEAR, PR_PREEN_OK },
101 /* Deleted inode has zero dtime */
103 "@D @i %i has zero dtime. ",
104 PROMPT_FIX, PR_PREEN_OK },
106 /* Inode in use, but dtime set */
108 "@i %i is in use, but has dtime set. ",
109 PROMPT_FIX, PR_PREEN_OK },
111 /* Zero-length directory */
112 { PR_1_ZERO_LENGTH_DIR,
113 "@i %i is a @z @d. ",
114 PROMPT_CLEAR, PR_PREEN_OK },
116 /* Block bitmap conflicts with some other fs block */
118 "@g %N's @b @B at %b @C.\n",
119 PROMPT_RELOCATE, 0 },
121 /* Inode bitmap conflicts with some other fs block */
123 "@g %N's @i @B at %b @C.\n",
124 PROMPT_RELOCATE, 0 },
126 /* Inode table conflicts with some other fs block */
127 { PR_1_ITABLE_CONFLICT,
128 "@g %g's @i table at %b @C.\n",
129 PROMPT_RELOCATE, 0 },
131 /* Block bitmap is on a bad block */
133 "@g %g's @b @B (%b) is bad. ",
134 PROMPT_RELOCATE, 0 },
136 /* Inode bitmap is on a bad block */
138 "@g %g's @i @B (%b) is bad. ",
139 PROMPT_RELOCATE, 0 },
141 /* Inode has incorrect i_size */
143 "@i %i, i_size is %Is, @s %N. ",
144 PROMPT_FIX, PR_PREEN_OK },
146 /* Inode has incorrect i_blocks */
148 "@i %i, i_blocks is %Ib, @s %N. ",
149 PROMPT_FIX, PR_PREEN_OK },
151 /* Illegal block number in inode */
152 { PR_1_ILLEGAL_BLOCK_NUM,
153 "Illegal @b #%B (%b) in @i %i. ",
154 PROMPT_CLEAR, PR_LATCH_BLOCK },
156 /* Block number overlaps fs metadata */
157 { PR_1_BLOCK_OVERLAPS_METADATA,
158 "@b #%B (%b) overlaps filesystem metadata in @i %i. ",
159 PROMPT_CLEAR, PR_LATCH_BLOCK },
161 /* Inode has illegal blocks (latch question) */
162 { PR_1_INODE_BLOCK_LATCH,
163 "@i %i has illegal @b(s). ",
166 /* Too many bad blocks in inode */
167 { PR_1_TOO_MANY_BAD_BLOCKS,
168 "Too many illegal @bs in @i %i.\n",
169 PROMPT_CLEAR_INODE, PR_NO_OK },
171 /* Illegal block number in bad block inode */
172 { PR_1_BB_ILLEGAL_BLOCK_NUM,
173 "Illegal @b #%B (%b) in bad @b @i. ",
174 PROMPT_CLEAR, PR_LATCH_BBLOCK },
176 /* Bad block inode has illegal blocks (latch question) */
177 { PR_1_INODE_BBLOCK_LATCH,
178 "Bad @b @i has illegal @b(s). ",
183 /* File has duplicate blocks */
185 "File %Q (@i #%i, mod time %IM) \n"
186 " has %B duplicate @b(s), shared with %N file(s):\n",
187 PROMPT_FIX, PR_MSG_ONLY },
189 /* List of files sharing duplicate blocks */
190 { PR_1B_DUP_FILE_LIST,
191 "\t%Q (@i #%i, mod time %IM)\n",
192 PROMPT_FIX, PR_MSG_ONLY },
197 /* Bad inode number for '.' */
198 { PR_2_BAD_INODE_DOT,
199 "Bad @i number for '.' in @d @i %i.\n",
202 /* Directory entry has bad inode number */
204 "@E has bad @i #: %Di.\n",
207 /* Directory entry has deleted or unused inode */
209 "@E has @D/unused @i %Di. ",
210 PROMPT_CLEAR, PR_PREEN_OK },
212 /* Directry entry is link to '.' */
217 /* Directory entry points to inode now located in a bad block */
219 "@E points to @i (%Di) located in a bad @b.\n",
222 /* Directory entry contains a link to a directory */
224 "@E @L to @d %P (%Di).\n",
227 /* Directory entry contains a link to the root directry */
229 "@E @L to the @r.\n",
232 /* Directory entry has illegal characters in its name */
234 "@E has illegal characters in its name.\n",
237 /* Missing '.' in directory inode */
239 "Missing '.' in @d @i %i.\n",
242 /* Missing '..' in directory inode */
243 { PR_2_MISSING_DOT_DOT,
244 "Missing '..' in @d @i %i.\n",
247 /* First entry in directory inode doesn't contain '.' */
249 "First @e '%Dn' (inode=%Di) in @d @i %i (%p) @s '.'\n",
252 /* Second entry in directory inode doesn't contain '..' */
253 { PR_2_2ND_NOT_DOT_DOT,
254 "Second @e '%Dn' (inode=%Di) in @d @i %i @s '..'\n",
257 /* i_faddr should be zero */
259 "i_faddr @F %IF, @s zero.\n",
262 /* i_file_acl should be zero */
263 { PR_2_FILE_ACL_ZERO,
264 "i_file_acl @F %If, @s zero.\n",
267 /* i_dir_acl should be zero */
269 "i_dir_acl @F %Id, @s zero.\n",
272 /* i_frag should be zero */
274 "i_frag @F %N, @s zero.\n",
277 /* i_fsize should be zero */
279 "i_fsize @F %N, @s zero.\n",
282 /* inode has bad mode */
284 "@i %i (%Q) has a bad mode (%Im).\n",
287 /* directory corrupted */
288 { PR_2_DIR_CORRUPTED,
289 "@d @i %i, @b %B, offset %N: @d corrupted\n",
292 /* filename too long */
293 { PR_2_FILENAME_LONG,
294 "@d @i %i, @b %B, offset %N: filename too long\n",
295 PROMPT_TRUNCATE, 0 },
297 /* Directory inode has a missing block (hole) */
298 { PR_2_DIRECTORY_HOLE,
299 "@d @i %i has an unallocated @b #%B. ",
300 PROMPT_ALLOCATE, 0 },
302 /* '.' is not NULL terminated */
303 { PR_2_DOT_NULL_TERM,
304 "'.' directory entry in @d @i %i is not NULL terminated\n",
307 /* '..' is not NULL terminated */
308 { PR_2_DOT_DOT_NULL_TERM,
309 "'..' directory entry in @d @i %i is not NULL terminated\n",
314 /* Root inode not allocated */
315 { PR_3_NO_ROOT_INODE,
316 "@r not allocated. ",
317 PROMPT_ALLOCATE, 0 },
319 /* No room in lost+found */
320 { PR_3_EXPAND_LF_DIR,
321 "No room in @l @d. ",
324 /* Unconnected directory inode */
325 { PR_3_UNCONNECTED_DIR,
326 "Unconnected @d @i %i (%p)\n",
329 /* /lost+found not found */
334 /* .. entry is incorrect */
336 "'..' in %Q (%i) is %P (%j), @s %q (%d).\n",
341 /* Unattached zero-length inode */
342 { PR_4_ZERO_LEN_INODE,
344 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
346 /* Unattached inode */
347 { PR_4_UNATTACHED_INODE,
351 /* Inode ref count wrong */
352 { PR_4_BAD_REF_COUNT,
353 "@i %i ref count is %Il, @s %N. ",
354 PROMPT_FIX, PR_PREEN_OK },
360 * This is the latch flags register. It allows several problems to be
361 * "latched" together. This means that the user has to answer but one
362 * question for the set of problems, and all of the associated
363 * problems will be either fixed or not fixed.
365 char pr_latch[7]; /* Latch flags register */
366 char pr_suppress[7]; /* Latch groups which are suppressed */
367 int latch_question[7] = {
368 PR_1_INODE_BLOCK_LATCH,
369 PR_1_INODE_BBLOCK_LATCH
372 static struct e2fsck_problem *find_problem(int code)
376 for (i=0; problem_table[i].e2p_code; i++) {
377 if (problem_table[i].e2p_code == code)
378 return &problem_table[i];
383 void reset_problem_latch(int mask)
385 pr_latch[PR_LATCH(mask)] = 0;
386 pr_suppress[PR_LATCH(mask)] = 0;
389 void suppress_latch_group(int mask, int value)
391 pr_suppress[PR_LATCH(mask)] = value;
394 void clear_problem_context(struct problem_context *ctx)
396 memset(ctx, 0, sizeof(struct problem_context));
401 int fix_problem(ext2_filsys fs, int code, struct problem_context *ctx)
403 struct e2fsck_problem *ptr;
406 int print_answer = 0;
409 ptr = find_problem(code);
411 printf("Unhandled error code (%d)!\n", code);
414 def_yn = (ptr->flags & PR_NO_DEFAULT) ? 0 : 1;
417 * Do special latch processing. This is where we ask the
418 * latch question, if it exists
420 if (ptr->flags & PR_LATCH_MASK) {
421 latch = PR_LATCH(ptr->flags);
422 if (latch_question[latch] && !pr_latch[latch])
423 pr_latch[latch] = fix_problem(fs,
424 latch_question[latch],
426 if (pr_suppress[latch])
432 printf("%s: ", device_name);
433 print_e2fsck_message(fs, ptr->e2p_description, ctx, 1);
435 if (!(ptr->flags & PR_PREEN_OK))
438 if (ptr->flags & PR_MSG_ONLY)
444 } else if (ptr->flags & PR_LATCH_MASK) {
445 latch = PR_LATCH(ptr->flags);
446 if (!pr_latch[latch])
448 ask(prompt[(int) ptr->prompt], def_yn) + 1;
451 answer = pr_latch[latch] - 1;
453 answer = ask(prompt[(int) ptr->prompt], def_yn);
454 if (!answer && !(ptr->flags & PR_NO_OK))
455 ext2fs_unmark_valid(fs);
459 answer ? preen_msg[(int) ptr->prompt] : "IGNORED");