Whamcloud - gitweb
Many files:
[tools/e2fsprogs.git] / e2fsck / problem.c
1 /*
2  * problem.c --- report filesystem problems to the user
3  *
4  * Copyright 1996, 1997 by 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 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <termios.h>
17
18 #include "e2fsck.h"
19
20 #include "problem.h"
21 #include "problemP.h"
22
23 #define PROMPT_NONE     0
24 #define PROMPT_FIX      1
25 #define PROMPT_CLEAR    2
26 #define PROMPT_RELOCATE 3
27 #define PROMPT_ALLOCATE 4
28 #define PROMPT_EXPAND   5
29 #define PROMPT_CONNECT  6
30 #define PROMPT_CREATE   7
31 #define PROMPT_SALVAGE  8
32 #define PROMPT_TRUNCATE 9
33 #define PROMPT_CLEAR_INODE 10
34 #define PROMPT_ABORT    11
35 #define PROMPT_SPLIT    12
36 #define PROMPT_CONTINUE 13
37 #define PROMPT_CLONE    14
38 #define PROMPT_DELETE   15
39 #define PROMPT_SUPPRESS 16
40 #define PROMPT_UNLINK   17
41
42 /*
43  * These are the prompts which are used to ask the user if they want
44  * to fix a problem.
45  */
46 static const char *prompt[] = {
47         "(no prompt)",          /* 0 */
48         "Fix",                  /* 1 */
49         "Clear",                /* 2 */
50         "Relocate",             /* 3 */
51         "Allocate",             /* 4 */
52         "Expand",               /* 5 */
53         "Connect to /lost+found", /* 6 */
54         "Create",               /* 7 */ 
55         "Salvage",              /* 8 */
56         "Truncate",             /* 9 */
57         "Clear inode",          /* 10 */
58         "Abort",                /* 11 */
59         "Split",                /* 12 */
60         "Continue",             /* 13 */
61         "Clone duplicate/bad blocks", /* 14 */
62         "Delete file",          /* 15 */
63         "Suppress messages",    /* 16 */
64         "Unlink",               /* 17 */
65 };
66
67 /*
68  * These messages are printed when we are preen mode and we will be
69  * automatically fixing the problem.
70  */
71 static const char *preen_msg[] = {
72         "(NONE)",               /* 0 */
73         "FIXED",                /* 1 */
74         "CLEARED",              /* 2 */
75         "RELOCATED",            /* 3 */
76         "ALLOCATED",            /* 4 */
77         "EXPANDED",             /* 5 */
78         "RECONNECTED",          /* 6 */
79         "CREATED",              /* 7 */
80         "SALVAGED",             /* 8 */
81         "TRUNCATED",            /* 9 */
82         "INODE CLEARED",        /* 10 */
83         "ABORTED",              /* 11 */
84         "SPLIT",                /* 12 */
85         "CONTINUING",           /* 13 */
86         "DUPLICATE/BAD BLOCKS CLONED", /* 14 */
87         "FILE DELETED",         /* 15 */
88         "SUPPRESSED",           /* 16 */
89         "UNLINKED",             /* 17 */
90 };
91
92 static const struct e2fsck_problem problem_table[] = {
93
94         /* Pre-Pass 1 errors */
95
96         /* Block bitmap not in group */
97         { PR_0_BB_NOT_GROUP, "@b @B for @g %g is not in @g.  (@b %b)\n",
98           PROMPT_RELOCATE, PR_LATCH_RELOC }, 
99
100         /* Inode bitmap not in group */
101         { PR_0_IB_NOT_GROUP, "@i @B for @g %g is not in @g.  (@b %b)\n",
102           PROMPT_RELOCATE, PR_LATCH_RELOC }, 
103
104         /* Inode table not in group */
105         { PR_0_ITABLE_NOT_GROUP,
106           "@i table for @g %g is not in @g.  (@b %b)\n"
107           "WARNING: SEVERE DATA LOSS POSSIBLE.\n",
108           PROMPT_RELOCATE, PR_LATCH_RELOC },
109
110         /* Superblock corrupt */
111         { PR_0_SB_CORRUPT,
112           "\nThe @S could not be read or does not describe a correct ext2\n"
113           "@f.  If the device is valid and it really contains an ext2\n"
114           "@f (and not swap or ufs or something else), then the @S\n"
115   "is corrupt, and you might try running e2fsck with an alternate @S:\n"
116           "    e2fsck -b %S <device>\n\n",
117           PROMPT_NONE, PR_FATAL },
118
119         /* Filesystem size is wrong */
120         { PR_0_FS_SIZE_WRONG,
121           "The @f size (according to the @S) is %b @bs\n"
122           "The physical size of the device is %c @bs\n"
123           "Either the @S or the partition table is likely to be corrupt!\n",
124           PROMPT_ABORT, 0 },
125
126         /* Fragments not supported */             
127         { PR_0_NO_FRAGMENTS,
128           "@S @b_size = %b, fragsize = %c.\n"
129           "This version of e2fsck does not support fragment sizes different\n"
130           "from the @b size.\n",
131           PROMPT_NONE, PR_FATAL },
132
133           /* Bad blocks_per_group */
134         { PR_0_BLOCKS_PER_GROUP,
135           "@S @bs_per_group = %b, should have been %c\n",
136           PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
137
138         /* Bad first_data_block */
139         { PR_0_FIRST_DATA_BLOCK,
140           "@S first_data_@b = %b, should have been %c\n",
141           PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
142         
143         /* Adding UUID to filesystem */
144         { PR_0_ADD_UUID,
145           "@f did not have a UUID; generating one.\n\n",
146           PROMPT_NONE, 0 },
147
148         /* Relocate hint */
149         { PR_0_RELOCATE_HINT,
150           "Note: if there is several inode or block bitmap blocks\n"
151           "which require relocation, or one part of the inode table\n"
152           "which must be moved, you may wish to try running e2fsck\n"
153           "with the '-b %S' option first.  The problem may lie only\n"
154           "with the primary block group descriptor, and the backup\n"
155           "block group descriptor may be OK.\n\n",
156           PROMPT_NONE, PR_PREEN_OK | PR_NOCOLLATE },
157
158         /* Miscellaneous superblock corruption */
159         { PR_0_MISC_CORRUPT_SUPER,
160           "Corruption found in @S.  (%s = %N).\n",        
161           PROMPT_NONE, PR_AFTER_CODE, PR_0_SB_CORRUPT },
162
163         /* Error determing physical device size of filesystem */
164         { PR_0_GETSIZE_ERROR,     
165           "Error determining size of the physical device: %m\n",
166           PROMPT_NONE, PR_FATAL },
167
168         /* Inode count in superblock is incorrect */
169         { PR_0_INODE_COUNT_WRONG,
170           "@i count in @S is %i, should be %j\n",
171           PROMPT_FIX, 0 },
172                   
173         /* Pass 1 errors */
174         
175         /* Pass 1: Checking inodes, blocks, and sizes */
176         { PR_1_PASS_HEADER,
177           "Pass 1: Checking @is, @bs, and sizes\n",
178           PROMPT_NONE, 0 },
179                   
180         /* Root directory is not an inode */
181         { PR_1_ROOT_NO_DIR, "@r is not a @d.  ",
182           PROMPT_CLEAR, 0 }, 
183
184         /* Root directory has dtime set */
185         { PR_1_ROOT_DTIME,
186           "@r has dtime set (probably due to old mke2fs).  ",
187           PROMPT_FIX, PR_PREEN_OK },
188
189         /* Reserved inode has bad mode */
190         { PR_1_RESERVED_BAD_MODE,
191           "Reserved @i %i has bad mode.  ",
192           PROMPT_CLEAR, PR_PREEN_OK },
193
194         /* Deleted inode has zero dtime */
195         { PR_1_ZERO_DTIME,
196           "@D @i %i has zero dtime.  ",
197           PROMPT_FIX, PR_PREEN_OK },
198
199         /* Inode in use, but dtime set */
200         { PR_1_SET_DTIME,
201           "@i %i is in use, but has dtime set.  ",
202           PROMPT_FIX, PR_PREEN_OK },
203
204         /* Zero-length directory */
205         { PR_1_ZERO_LENGTH_DIR,
206           "@i %i is a @z @d.  ",
207           PROMPT_CLEAR, PR_PREEN_OK },
208
209         /* Block bitmap conflicts with some other fs block */
210         { PR_1_BB_CONFLICT,
211           "@g %g's @b @B at %b @C.\n",
212           PROMPT_RELOCATE, 0 },
213
214         /* Inode bitmap conflicts with some other fs block */
215         { PR_1_IB_CONFLICT,
216           "@g %g's @i @B at %b @C.\n",
217           PROMPT_RELOCATE, 0 },
218
219         /* Inode table conflicts with some other fs block */
220         { PR_1_ITABLE_CONFLICT,
221           "@g %g's @i table at %b @C.\n",
222           PROMPT_RELOCATE, 0 },
223
224         /* Block bitmap is on a bad block */
225         { PR_1_BB_BAD_BLOCK,
226           "@g %g's @b @B (%b) is bad.  ",
227           PROMPT_RELOCATE, 0 },
228
229         /* Inode bitmap is on a bad block */
230         { PR_1_IB_BAD_BLOCK,
231           "@g %g's @i @B (%b) is bad.  ",
232           PROMPT_RELOCATE, 0 },
233
234         /* Inode has incorrect i_size */
235         { PR_1_BAD_I_SIZE,
236           "@i %i, i_size is %Is, @s %N.  ",
237           PROMPT_FIX, PR_PREEN_OK },
238                   
239         /* Inode has incorrect i_blocks */
240         { PR_1_BAD_I_BLOCKS,
241           "@i %i, i_@bs is %Ib, @s %N.  ",
242           PROMPT_FIX, PR_PREEN_OK },
243
244         /* Illegal block number in inode */
245         { PR_1_ILLEGAL_BLOCK_NUM,
246           "@I @b #%B (%b) in @i %i.  ",
247           PROMPT_CLEAR, PR_LATCH_BLOCK },
248
249         /* Block number overlaps fs metadata */
250         { PR_1_BLOCK_OVERLAPS_METADATA,
251           "@b #%B (%b) overlaps @f metadata in @i %i.  ",
252           PROMPT_CLEAR, PR_LATCH_BLOCK },
253
254         /* Inode has illegal blocks (latch question) */
255         { PR_1_INODE_BLOCK_LATCH,
256           "@i %i has illegal @b(s).  ",
257           PROMPT_CLEAR, 0 },
258
259         /* Too many bad blocks in inode */
260         { PR_1_TOO_MANY_BAD_BLOCKS,
261           "Too many illegal @bs in @i %i.\n",
262           PROMPT_CLEAR_INODE, PR_NO_OK },       
263
264         /* Illegal block number in bad block inode */
265         { PR_1_BB_ILLEGAL_BLOCK_NUM,
266           "@I @b #%B (%b) in bad @b @i.  ",
267           PROMPT_CLEAR, PR_LATCH_BBLOCK },
268
269         /* Bad block inode has illegal blocks (latch question) */
270         { PR_1_INODE_BBLOCK_LATCH,
271           "Bad @b @i has illegal @b(s).  ",
272           PROMPT_CLEAR, 0 },
273
274         /* Duplicate or bad blocks in use! */
275         { PR_1_DUP_BLOCKS_PREENSTOP,
276           "Duplicate or bad @b in use!\n",
277           PROMPT_NONE, 0 },
278
279         /* Bad block used as bad block indirect block */          
280         { PR_1_BBINODE_BAD_METABLOCK,
281           "Bad @b %b used as bad @b indirect @b?!?\n",
282           PROMPT_NONE, PR_AFTER_CODE, PR_1_BBINODE_BAD_METABLOCK_PROMPT },
283
284         /* Inconsistency can't be fixed prompt */         
285         { PR_1_BBINODE_BAD_METABLOCK_PROMPT,
286           "\nThis inconsistency can not be fixed with e2fsck; to fix it, use\n"
287           """dumpe2fs -b"" to dump out the bad @b "
288           "list and ""e2fsck -L filename""\n"
289           "to read it back in again.\n",
290           PROMPT_CONTINUE, PR_PREEN_NOMSG },
291
292         /* Bad primary block */
293         { PR_1_BAD_PRIMARY_BLOCK,  
294           "\nIf the @b is really bad, the @f can not be fixed.\n",
295           PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK_PROMPT },
296                   
297         /* Bad primary block prompt */
298         { PR_1_BAD_PRIMARY_BLOCK_PROMPT,          
299           "You can clear the this @b (and hope for the best) from the\n"
300           "bad @b list and hope that @b is really OK, but there are no\n"
301           "guarantees.\n\n",
302           PROMPT_CLEAR, PR_PREEN_NOMSG },
303
304         /* Bad primary superblock */
305         { PR_1_BAD_PRIMARY_SUPERBLOCK,
306           "The primary @S (%b) is on the bad @b list.\n",
307           PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
308                   
309         /* Bad primary block group descriptors */
310         { PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR,
311           "Block %b in the primary @g descriptors "
312           "is on the bad @b list\n",
313           PROMPT_NONE, PR_AFTER_CODE, PR_1_BAD_PRIMARY_BLOCK },
314                   
315         /* Bad superblock in group */
316         { PR_1_BAD_SUPERBLOCK,
317           "Warning: Group %g's @S (%b) is bad.\n",
318           PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
319                   
320         /* Bad block group descriptors in group */
321         { PR_1_BAD_GROUP_DESCRIPTORS,
322           "Warning: Group %g's copy of the @g descriptors has a bad "
323           "@b (%b).\n",
324           PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
325
326         /* Block claimed for no reason */         
327         { PR_1_PROGERR_CLAIMED_BLOCK,
328           "Programming error?  @b #%b claimed for no reason in "
329           "process_bad_@b.\n",
330           PROMPT_NONE, PR_PREEN_OK },
331
332         /* Error allocating blocks for relocating metadata */
333         { PR_1_RELOC_BLOCK_ALLOCATE,
334           "@A %N @b(s) for %s: %m\n",
335           PROMPT_NONE, PR_PREEN_OK },
336                 
337         /* Error allocating block buffer during relocation process */
338         { PR_1_RELOC_MEMORY_ALLOCATE,
339           "@A @b buffer for relocating %s\n",
340           PROMPT_NONE, PR_PREEN_OK },
341                 
342         /* Relocating metadata group information from X to Y */ 
343         { PR_1_RELOC_FROM_TO,
344           "Relocating @g %g's %s from %b to %c...\n",
345           PROMPT_NONE, PR_PREEN_OK },
346                 
347         /* Relocating metatdata group information to X */
348         { PR_1_RELOC_TO,
349           "Relocating @g %g's %s to %c...\n",
350           PROMPT_NONE, PR_PREEN_OK },
351                 
352         /* Block read error during relocation process */
353         { PR_1_RELOC_READ_ERR,
354           "Warning: could not read @b %b of %s: %m\n",
355           PROMPT_NONE, PR_PREEN_OK },
356                 
357         /* Block write error during relocation process */
358         { PR_1_RELOC_WRITE_ERR,
359           "Warning: could not write @b %b for %s: %m\n",
360           PROMPT_NONE, PR_PREEN_OK },
361
362         /* Error allocating inode bitmap */
363         { PR_1_ALLOCATE_IBITMAP_ERROR,
364           "@A @i @B (%N): %m\n",
365           PROMPT_NONE, PR_FATAL },
366
367         /* Error allocating block bitmap */
368         { PR_1_ALLOCATE_BBITMAP_ERROR,
369           "@A @b @B (%N): %m\n",
370           PROMPT_NONE, PR_FATAL },
371
372         /* Error allocating icount structure */
373         { PR_1_ALLOCATE_ICOUNT,
374           "@A icount link information: %m\n",
375           PROMPT_NONE, PR_FATAL },
376
377         /* Error allocating dbcount */
378         { PR_1_ALLOCATE_DBCOUNT,
379           "@A @d @b array: %m\n",
380           PROMPT_NONE, PR_FATAL },
381
382         /* Error while scanning inodes */
383         { PR_1_ISCAN_ERROR,
384           "Error while scanning @is (%i): %m\n",
385           PROMPT_NONE, PR_FATAL },
386
387         /* Error while iterating over blocks */
388         { PR_1_BLOCK_ITERATE,
389           "Error while iterating over blocks in @i %i: %m\n",
390           PROMPT_NONE, PR_FATAL },
391
392         /* Error while storing inode count information */         
393         { PR_1_ICOUNT_STORE,
394           "Error storing @i count information (inode=%i, count=%N): %m\n",
395           PROMPT_NONE, PR_FATAL },
396
397         /* Error while storing directory block information */     
398         { PR_1_ADD_DBLOCK,
399           "Error storing @d @b information "
400           "(inode=%i, block=%b, num=%N): %m\n",
401           PROMPT_NONE, PR_FATAL },
402
403         /* Error while reading inode (for clearing) */    
404         { PR_1_READ_INODE,
405           "Error reading @i %i: %m\n",
406           PROMPT_NONE, PR_FATAL },
407
408         /* Suppress messages prompt */
409         { PR_1_SUPPRESS_MESSAGES, "", PROMPT_SUPPRESS, PR_NO_OK },
410                   
411         /* Filesystem contains large files, but has no such flag in sb */
412         { PR_1_FEATURE_LARGE_FILES,
413           "@f contains large files, but lacks LARGE_FILE flag in @S.\n",
414           PROMPT_FIX, 0 },
415           
416         /* Pass 1b errors */
417
418         /* Pass 1B: Rescan for duplicate/bad blocks */
419         { PR_1B_PASS_HEADER,
420           "Duplicate @bs found... invoking duplicate @b passes.\n"
421           "Pass 1B: Rescan for duplicate/bad @bs\n",
422           PROMPT_NONE, 0 },
423
424         /* Duplicate/bad block(s) header */
425         { PR_1B_DUP_BLOCK_HEADER,         
426           "Duplicate/bad @b(s) in @i %i:",
427           PROMPT_NONE, 0 },
428
429         /* Duplicate/bad block(s) in inode */
430         { PR_1B_DUP_BLOCK,        
431           " %b",
432           PROMPT_NONE, PR_LATCH_DBLOCK },
433
434         /* Duplicate/bad block(s) end */
435         { PR_1B_DUP_BLOCK_END,
436           "\n",
437           PROMPT_NONE, 0 },
438                   
439         /* Error while scanning inodes */
440         { PR_1B_ISCAN_ERROR,
441           "Error while scanning inodes (%i): %m\n",
442           PROMPT_NONE, PR_FATAL },
443
444         /* Error allocating inode bitmap */
445         { PR_1B_ALLOCATE_IBITMAP_ERROR,
446           "@A @i @B (inode_dup_map): %m\n",
447           PROMPT_NONE, PR_FATAL },
448
449
450         /* Pass 1C: Scan directories for inodes with dup blocks. */
451         { PR_1C_PASS_HEADER,
452           "Pass 1C: Scan directories for @is with dup @bs.\n",
453           PROMPT_NONE, 0 },
454
455                   
456         /* Pass 1D: Reconciling duplicate blocks */
457         { PR_1D_PASS_HEADER,
458           "Pass 1D: Reconciling duplicate @bs\n",
459           PROMPT_NONE, 0 },
460                   
461         /* File has duplicate blocks */
462         { PR_1D_DUP_FILE,
463           "File %Q (@i #%i, mod time %IM) \n"
464           "  has %B duplicate @b(s), shared with %N file(s):\n",
465           PROMPT_NONE, 0 },
466                   
467         /* List of files sharing duplicate blocks */    
468         { PR_1D_DUP_FILE_LIST,
469           "\t%Q (@i #%i, mod time %IM)\n",
470           PROMPT_NONE, 0 },
471           
472         /* File sharing blocks with filesystem metadata  */     
473         { PR_1D_SHARE_METADATA,
474           "\t<@f metadata>\n",
475           PROMPT_NONE, 0 },
476
477         /* Report of how many duplicate/bad inodes */   
478         { PR_1D_NUM_DUP_INODES,
479           "(There are %N @is containing duplicate/bad @bs.)\n\n",
480           PROMPT_NONE, 0 },
481
482         /* Duplicated blocks already reassigned or cloned. */
483         { PR_1D_DUP_BLOCKS_DEALT,
484           "Duplicated @bs already reassigned or cloned.\n\n",
485           PROMPT_NONE, 0 },
486
487         /* Clone duplicate/bad blocks? */
488         { PR_1D_CLONE_QUESTION,
489           "", PROMPT_CLONE, PR_NO_OK },
490                   
491         /* Delete file? */
492         { PR_1D_DELETE_QUESTION,
493           "", PROMPT_DELETE, 0 },
494
495         /* Couldn't clone file (error) */
496         { PR_1D_CLONE_ERROR,
497           "Couldn't clone file: %m\n", PROMPT_NONE, 0 },
498
499         /* Pass 2 errors */
500
501         /* Pass 2: Checking directory structure */
502         { PR_2_PASS_HEADER,
503           "Pass 2: Checking @d structure\n",
504           PROMPT_NONE, 0 },
505                   
506         /* Bad inode number for '.' */
507         { PR_2_BAD_INODE_DOT,
508           "Bad @i number for '.' in @d @i %i.\n",
509           PROMPT_FIX, 0 },
510
511         /* Directory entry has bad inode number */
512         { PR_2_BAD_INO, 
513           "@E has bad @i #: %Di.\n",
514           PROMPT_CLEAR, 0 },
515
516         /* Directory entry has deleted or unused inode */
517         { PR_2_UNUSED_INODE, 
518           "@E has @D/unused @i %Di.  ",
519           PROMPT_CLEAR, PR_PREEN_OK },
520
521         /* Directry entry is link to '.' */
522         { PR_2_LINK_DOT, 
523           "@E @L to '.'  ",
524           PROMPT_CLEAR, 0 },
525
526         /* Directory entry points to inode now located in a bad block */
527         { PR_2_BB_INODE,
528           "@E points to @i (%Di) located in a bad @b.\n",
529           PROMPT_CLEAR, 0 },
530
531         /* Directory entry contains a link to a directory */
532         { PR_2_LINK_DIR, 
533           "@E @L to @d %P (%Di).\n",
534           PROMPT_CLEAR, 0 },
535
536         /* Directory entry contains a link to the root directry */
537         { PR_2_LINK_ROOT, 
538           "@E @L to the @r.\n",
539           PROMPT_CLEAR, 0 },
540
541         /* Directory entry has illegal characters in its name */
542         { PR_2_BAD_NAME, 
543           "@E has illegal characters in its name.\n",
544           PROMPT_FIX, 0 },
545
546         /* Missing '.' in directory inode */      
547         { PR_2_MISSING_DOT,
548           "Missing '.' in @d @i %i.\n",
549           PROMPT_FIX, 0 },
550
551         /* Missing '..' in directory inode */     
552         { PR_2_MISSING_DOT_DOT,
553           "Missing '..' in @d @i %i.\n",
554           PROMPT_FIX, 0 },
555
556         /* First entry in directory inode doesn't contain '.' */
557         { PR_2_1ST_NOT_DOT,
558           "First @e '%Dn' (inode=%Di) in @d @i %i (%p) @s '.'\n",
559           PROMPT_FIX, 0 },
560
561         /* Second entry in directory inode doesn't contain '..' */
562         { PR_2_2ND_NOT_DOT_DOT,
563           "Second @e '%Dn' (inode=%Di) in @d @i %i @s '..'\n",
564           PROMPT_FIX, 0 },
565                   
566         /* i_faddr should be zero */
567         { PR_2_FADDR_ZERO,
568           "i_faddr @F %IF, @s zero.\n",
569           PROMPT_CLEAR, 0 },
570
571         /* i_file_acl should be zero */
572         { PR_2_FILE_ACL_ZERO,
573           "i_file_acl @F %If, @s zero.\n",
574           PROMPT_CLEAR, 0 },
575
576         /* i_dir_acl should be zero */
577         { PR_2_DIR_ACL_ZERO,
578           "i_dir_acl @F %Id, @s zero.\n",
579           PROMPT_CLEAR, 0 },
580
581         /* i_frag should be zero */
582         { PR_2_FRAG_ZERO,
583           "i_frag @F %N, @s zero.\n",
584           PROMPT_CLEAR, 0 },
585
586         /* i_fsize should be zero */
587         { PR_2_FSIZE_ZERO,
588           "i_fsize @F %N, @s zero.\n",
589           PROMPT_CLEAR, 0 },
590
591         /* inode has bad mode */
592         { PR_2_BAD_MODE,
593           "@i %i (%Q) has a bad mode (%Im).\n",
594           PROMPT_CLEAR, 0 },
595
596         /* directory corrupted */
597         { PR_2_DIR_CORRUPTED,     
598           "@d @i %i, @b %B, offset %N: @d corrupted\n",
599           PROMPT_SALVAGE, 0 },
600                   
601         /* filename too long */
602         { PR_2_FILENAME_LONG,     
603           "@d @i %i, @b %B, offset %N: filename too long\n",
604           PROMPT_TRUNCATE, 0 },
605
606         /* Directory inode has a missing block (hole) */
607         { PR_2_DIRECTORY_HOLE,    
608           "@d @i %i has an unallocated @b #%B.  ",
609           PROMPT_ALLOCATE, 0 },
610
611         /* '.' is not NULL terminated */
612         { PR_2_DOT_NULL_TERM,
613           "'.' @d @e in @d @i %i is not NULL terminated\n",
614           PROMPT_FIX, 0 },
615
616         /* '..' is not NULL terminated */
617         { PR_2_DOT_DOT_NULL_TERM,
618           "'..' @d @e in @d @i %i is not NULL terminated\n",
619           PROMPT_FIX, 0 },
620
621         /* Illegal character device inode */
622         { PR_2_BAD_CHAR_DEV,
623           "@i %i (%Q) is an @I character device.\n",
624           PROMPT_CLEAR, 0 },
625
626         /* Illegal block device inode */
627         { PR_2_BAD_BLOCK_DEV,
628           "@i %i (%Q) is an @I @b device.\n",
629           PROMPT_CLEAR, 0 },
630
631         /* Duplicate '.' entry */
632         { PR_2_DUP_DOT,
633           "@E is duplicate '.' @e.\n",
634           PROMPT_FIX, 0 },        
635
636         /* Duplicate '..' entry */
637         { PR_2_DUP_DOT_DOT,
638           "@E is duplicate '..' @e.\n",
639           PROMPT_FIX, 0 },
640
641         /* Internal error: couldn't find dir_info */
642         { PR_2_NO_DIRINFO,
643           "Internal error: couldn't find dir_info for %i.\n",
644           PROMPT_NONE, PR_FATAL },
645
646         /* Final rec_len is wrong */
647         { PR_2_FINAL_RECLEN,
648           "@E has rec_len of %dr, should be %N.\n",
649           PROMPT_FIX, 0 },
650                   
651         /* Error allocating icount structure */
652         { PR_2_ALLOCATE_ICOUNT,
653           "@A icount structure: %m\n",
654           PROMPT_NONE, PR_FATAL },
655
656         /* Error iterating over directory blocks */
657         { PR_2_DBLIST_ITERATE,
658           "Error interating over @d @bs: %m\n",
659           PROMPT_NONE, PR_FATAL },
660
661         /* Error reading directory block */
662         { PR_2_READ_DIRBLOCK,
663           "Error reading @d @b %b (@i %i): %m\n",
664           PROMPT_CONTINUE, 0 },
665
666         /* Error writing directory block */
667         { PR_2_WRITE_DIRBLOCK,
668           "Error writing @d @b %b (@i %i): %m\n",
669           PROMPT_CONTINUE, 0 },
670
671         /* Error allocating new directory block */
672         { PR_2_ALLOC_DIRBOCK,
673           "@A new @d @b for @i %i (%s): %m\n",
674           PROMPT_NONE, 0 },
675
676         /* Error deallocating inode */
677         { PR_2_DEALLOC_INODE,
678           "Error deallocating @i %i: %m\n",
679           PROMPT_NONE, PR_FATAL },
680
681         /* Directory entry for '.' is big.  Split? */
682         { PR_2_SPLIT_DOT,
683           "@d @e for '.' is big.  ",
684           PROMPT_SPLIT, PR_NO_OK },
685
686         /* Illegal FIFO inode */
687         { PR_2_BAD_FIFO,
688           "@i %i (%Q) is an @I FIFO.\n",
689           PROMPT_CLEAR, 0 },
690
691         /* Illegal socket inode */
692         { PR_2_BAD_SOCKET,
693           "@i %i (%Q) is an @I socket.\n",
694           PROMPT_CLEAR, 0 },
695
696         /* Directory filetype not set */
697         { PR_2_SET_FILETYPE,
698           "Setting filetype for @E to %N.\n",
699           PROMPT_NONE, PR_PREEN_OK | PR_NO_OK | PR_NO_NOMSG },
700
701         /* Directory filetype incorrect */
702         { PR_2_BAD_FILETYPE,
703           "@E has an incorrect filetype (was %dt, should be %N)\n",
704           PROMPT_FIX, 0 },
705
706         /* Pass 3 errors */
707
708         /* Pass 3: Checking directory connectivity */
709         { PR_3_PASS_HEADER,
710           "Pass 3: Checking @d connectivity\n",
711           PROMPT_NONE, 0 },
712                   
713         /* Root inode not allocated */
714         { PR_3_NO_ROOT_INODE,
715           "@r not allocated.  ",
716           PROMPT_ALLOCATE, 0 }, 
717                   
718         /* No room in lost+found */
719         { PR_3_EXPAND_LF_DIR,
720           "No room in @l @d.  ",
721           PROMPT_EXPAND, 0 },
722
723         /* Unconnected directory inode */
724         { PR_3_UNCONNECTED_DIR,
725           "Unconnected @d @i %i (%p)\n",
726           PROMPT_CONNECT, 0 },
727
728         /* /lost+found not found */
729         { PR_3_NO_LF_DIR,
730           "/@l not found.  ",
731           PROMPT_CREATE, PR_PREEN_OK },
732
733         /* .. entry is incorrect */
734         { PR_3_BAD_DOT_DOT,
735           "'..' in %Q (%i) is %P (%j), @s %q (%d).\n",
736           PROMPT_FIX, 0 },
737
738         /* Bad or non-existent /lost+found.  Cannot reconnect */
739         { PR_3_NO_LPF,
740           "Bad or non-existent /@l.  Cannot reconnect\n",
741           PROMPT_NONE, 0 },
742
743         /* Could not expand /lost+found */
744         { PR_3_CANT_EXPAND_LPF,
745           "Could not expand /@l: %m\n",
746           PROMPT_NONE, 0 },
747
748         /* Could not reconnect inode */
749         { PR_3_CANT_RECONNECT,
750           "Could not reconnect %i: %m\n",
751           PROMPT_NONE, 0 },
752
753         /* Error while trying to find /lost+found */
754         { PR_3_ERR_FIND_LPF,
755           "Error while trying to find /@l: %m\n",
756           PROMPT_NONE, 0 },
757
758         /* Error in ext2fs_new_block while creating /lost+found */
759         { PR_3_ERR_LPF_NEW_BLOCK, 
760           "ext2fs_new_@b: %m while trying to create /@l @d\n",
761           PROMPT_NONE, 0 },
762                   
763         /* Error in ext2fs_new_inode while creating /lost+found */
764         { PR_3_ERR_LPF_NEW_INODE,
765           "ext2fs_new_@i: %m while trying to create /@l @d\n",
766           PROMPT_NONE, 0 },
767
768         /* Error in ext2fs_new_dir_block while creating /lost+found */    
769         { PR_3_ERR_LPF_NEW_DIR_BLOCK,
770           "ext2fs_new_dir_@b: %m while creating new @d @b\n",
771           PROMPT_NONE, 0 },
772                   
773         /* Error while writing directory block for /lost+found */
774         { PR_3_ERR_LPF_WRITE_BLOCK,
775           "ext2fs_write_dir_@b: %m while writing the @d @b for /@l\n",
776           PROMPT_NONE, 0 },
777
778         /* Error while adjusting inode count */
779         { PR_3_ADJUST_INODE,
780           "Error while adjusting @i count on @i %i\n",
781           PROMPT_NONE, 0 },
782
783         /* Couldn't fix parent directory -- error */
784         { PR_3_FIX_PARENT_ERR,
785           "Couldn't fix parent of @i %i: %m\n\n",
786           PROMPT_NONE, 0 },
787
788         /* Couldn't fix parent directory -- couldn't find it */   
789         { PR_3_FIX_PARENT_NOFIND,
790           "Couldn't fix parent of @i %i: Couldn't find parent @d entry\n\n",
791           PROMPT_NONE, 0 },
792
793         /* Error allocating inode bitmap */
794         { PR_3_ALLOCATE_IBITMAP_ERROR,
795           "@A @i @B (%N): %m\n",
796           PROMPT_NONE, PR_FATAL },
797
798         /* Error creating root directory */
799         { PR_3_CREATE_ROOT_ERROR,
800           "Error creating root @d (%s): %m\n",
801           PROMPT_NONE, PR_FATAL },        
802
803         /* Error creating lost and found directory */
804         { PR_3_CREATE_LPF_ERROR,
805           "Error creating /@l @d (%s): %m\n",
806           PROMPT_NONE, PR_FATAL },  
807
808         /* Root inode is not directory; aborting */
809         { PR_3_ROOT_NOT_DIR_ABORT,
810           "@r is not a @d; aborting.\n",
811           PROMPT_NONE, PR_FATAL },  
812
813         /* Cannot proceed without a root inode. */
814         { PR_3_NO_ROOT_INODE_ABORT,
815           "Cannot proceed without a @r.\n",
816           PROMPT_NONE, PR_FATAL },  
817
818         /* Internal error: couldn't find dir_info */
819         { PR_3_NO_DIRINFO,
820           "Internal error: couldn't find dir_info for %i.\n",
821           PROMPT_NONE, PR_FATAL },
822
823         /* Lost+found not a directory */
824         { PR_3_LPF_NOTDIR,
825           "/@l is not a @d (ino=%i)\n",
826           PROMPT_UNLINK, 0 }, 
827
828         /* Pass 4 errors */
829         
830         /* Pass 4: Checking reference counts */
831         { PR_4_PASS_HEADER,
832           "Pass 4: Checking reference counts\n",
833           PROMPT_NONE, 0 },
834                   
835         /* Unattached zero-length inode */
836         { PR_4_ZERO_LEN_INODE,
837           "@u @z @i %i.  ",
838           PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK },
839
840         /* Unattached inode */
841         { PR_4_UNATTACHED_INODE,
842           "@u @i %i\n",
843           PROMPT_CONNECT, 0 },
844
845         /* Inode ref count wrong */
846         { PR_4_BAD_REF_COUNT,
847           "@i %i ref count is %Il, @s %N.  ",
848           PROMPT_FIX, PR_PREEN_OK },
849
850         { PR_4_INCONSISTENT_COUNT,
851           "WARNING: PROGRAMMING BUG IN E2FSCK!\n"
852           "\tOR SOME BONEHEAD (YOU) IS CHECKING A MOUNTED (LIVE) FILESYSTEM.\n"
853           "@i_link_info[%i] is %N, @i.i_links_count is %Il.  "
854           "They should be the same!\n",
855           PROMPT_NONE, 0 },
856
857         /* Pass 5 errors */
858                   
859         /* Pass 5: Checking group summary information */
860         { PR_5_PASS_HEADER,
861           "Pass 5: Checking @g summary information\n",
862           PROMPT_NONE, 0 },
863                   
864         /* Padding at end of inode bitmap is not set. */
865         { PR_5_INODE_BMAP_PADDING,
866           "Padding at end of @i @B is not set. ",
867           PROMPT_FIX, PR_PREEN_OK },
868                   
869         /* Padding at end of block bitmap is not set. */
870         { PR_5_BLOCK_BMAP_PADDING,
871           "Padding at end of @b @B is not set. ",
872           PROMPT_FIX, PR_PREEN_OK },
873                 
874         /* Block bitmap differences header */
875         { PR_5_BLOCK_BITMAP_HEADER,
876           "@b @B differences: ",
877           PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG},
878
879         /* Block not used, but marked in bitmap */
880         { PR_5_UNUSED_BLOCK,
881           " -%b",
882           PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
883                   
884         /* Block used, but not marked used in bitmap */
885         { PR_5_BLOCK_USED,
886           " +%b",
887           PROMPT_NONE, PR_LATCH_BBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
888
889         /* Block bitmap differences end */        
890         { PR_5_BLOCK_BITMAP_END,
891           "\n",
892           PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
893
894         /* Inode bitmap differences header */
895         { PR_5_INODE_BITMAP_HEADER,
896           "@i @B differences: ",
897           PROMPT_NONE, PR_PREEN_OK | PR_PREEN_NOMSG },
898
899         /* Inode not used, but marked in bitmap */
900         { PR_5_UNUSED_INODE,
901           " -%i",
902           PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
903                   
904         /* Inode used, but not marked used in bitmap */
905         { PR_5_INODE_USED,
906           " +%i",
907           PROMPT_NONE, PR_LATCH_IBITMAP | PR_PREEN_OK | PR_PREEN_NOMSG },
908
909         /* Inode bitmap differences end */        
910         { PR_5_INODE_BITMAP_END,
911           "\n",
912           PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
913
914         /* Free inodes count for group wrong */
915         { PR_5_FREE_INODE_COUNT_GROUP,
916           "Free @is count wrong for @g #%g (%i, counted=%j).\n",
917           PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
918
919         /* Directories count for group wrong */
920         { PR_5_FREE_DIR_COUNT_GROUP,
921           "Directories count wrong for @g #%g (%i, counted=%j).\n",
922           PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
923
924         /* Free inodes count wrong */
925         { PR_5_FREE_INODE_COUNT,
926           "Free @is count wrong (%i, counted=%j).\n",
927           PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
928
929         /* Free blocks count for group wrong */
930         { PR_5_FREE_BLOCK_COUNT_GROUP,
931           "Free @bs count wrong for @g #%g (%b, counted=%c).\n",
932           PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
933
934         /* Free blocks count wrong */
935         { PR_5_FREE_BLOCK_COUNT,
936           "Free @bs count wrong (%b, counted=%c).\n",
937           PROMPT_FIX, PR_PREEN_OK | PR_PREEN_NOMSG },
938
939         /* Programming error: bitmap endpoints don't match */
940         { PR_5_BMAP_ENDPOINTS,
941           "PROGRAMMING ERROR: @f (#%N) @B endpoints (%b, %c) don't "
942           "match calculated @B endpoints (%i, %j)\n",
943           PROMPT_NONE, PR_FATAL },
944
945         /* Internal error: fudging end of bitmap */
946         { PR_5_FUDGE_BITMAP_ERROR,
947           "Internal error: fudging end of bitmap (%N)\n",
948           PROMPT_NONE, PR_FATAL },        
949           
950         { 0 }
951 };
952
953 /*
954  * This is the latch flags register.  It allows several problems to be
955  * "latched" together.  This means that the user has to answer but one
956  * question for the set of problems, and all of the associated
957  * problems will be either fixed or not fixed.
958  */
959 static struct latch_descr pr_latch_info[] = {
960         { PR_LATCH_BLOCK, PR_1_INODE_BLOCK_LATCH, 0 },
961         { PR_LATCH_BBLOCK, PR_1_INODE_BBLOCK_LATCH, 0 },
962         { PR_LATCH_IBITMAP, PR_5_INODE_BITMAP_HEADER, PR_5_INODE_BITMAP_END },
963         { PR_LATCH_BBITMAP, PR_5_BLOCK_BITMAP_HEADER, PR_5_BLOCK_BITMAP_END },
964         { PR_LATCH_RELOC, PR_0_RELOCATE_HINT, 0 },
965         { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
966         { -1, 0, 0 },
967 };
968
969 static const struct e2fsck_problem *find_problem(int code)
970 {
971         int     i;
972
973         for (i=0; problem_table[i].e2p_code; i++) {
974                 if (problem_table[i].e2p_code == code)
975                         return &problem_table[i];
976         }
977         return 0;
978 }
979
980 static struct latch_descr *find_latch(int code)
981 {
982         int     i;
983
984         for (i=0; pr_latch_info[i].latch_code >= 0; i++) {
985                 if (pr_latch_info[i].latch_code == code)
986                         return &pr_latch_info[i];
987         }
988         return 0;
989 }
990
991 int end_problem_latch(e2fsck_t ctx, int mask)
992 {
993         struct latch_descr *ldesc;
994         struct problem_context pctx;
995         int answer = -1;
996         
997         ldesc = find_latch(mask);
998         if (ldesc->end_message && (ldesc->flags & PRL_LATCHED)) {
999                 clear_problem_context(&pctx);
1000                 answer = fix_problem(ctx, ldesc->end_message, &pctx);
1001         }
1002         ldesc->flags &= ~(PRL_VARIABLE);
1003         return answer;
1004 }
1005
1006 int set_latch_flags(int mask, int setflags, int clearflags)
1007 {
1008         struct latch_descr *ldesc;
1009
1010         ldesc = find_latch(mask);
1011         if (!ldesc)
1012                 return -1;
1013         ldesc->flags |= setflags;
1014         ldesc->flags &= ~clearflags;
1015         return 0;
1016 }
1017
1018 int get_latch_flags(int mask, int *value)
1019 {
1020         struct latch_descr *ldesc;
1021
1022         ldesc = find_latch(mask);
1023         if (!ldesc)
1024                 return -1;
1025         *value = ldesc->flags;
1026         return 0;
1027 }
1028
1029 void clear_problem_context(struct problem_context *ctx)
1030 {
1031         memset(ctx, 0, sizeof(struct problem_context));
1032         ctx->blkcount = -1;
1033         ctx->group = -1;
1034 }
1035
1036 int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
1037 {
1038         ext2_filsys fs = ctx->fs;
1039         const struct e2fsck_problem *ptr;
1040         struct latch_descr *ldesc = 0;
1041         const char *message;
1042         int             def_yn, answer, ans;
1043         int             print_answer = 0;
1044         int             suppress = 0;
1045
1046         ptr = find_problem(code);
1047         if (!ptr) {
1048                 printf("Unhandled error code (%d)!\n", code);
1049                 return 0;
1050         }
1051         def_yn = 1;
1052         if ((ptr->flags & PR_NO_DEFAULT) || (ctx->options & E2F_OPT_NO))
1053                 def_yn= 0;
1054
1055         /*
1056          * Do special latch processing.  This is where we ask the
1057          * latch question, if it exists
1058          */
1059         if (ptr->flags & PR_LATCH_MASK) {
1060                 ldesc = find_latch(ptr->flags & PR_LATCH_MASK);
1061                 if (ldesc->question && !(ldesc->flags & PRL_LATCHED)) {
1062                         ans = fix_problem(ctx, ldesc->question, pctx);
1063                         if (ans == 1)
1064                                 ldesc->flags |= PRL_YES;
1065                         if (ans == 0)
1066                                 ldesc->flags |= PRL_NO;
1067                         ldesc->flags |= PRL_LATCHED;
1068                 }
1069                 if (ldesc->flags & PRL_SUPPRESS)
1070                         suppress++;
1071         }
1072         if ((ptr->flags & PR_PREEN_NOMSG) &&
1073             (ctx->options & E2F_OPT_PREEN))
1074                 suppress++;
1075         if ((ptr->flags & PR_NO_NOMSG) &&
1076             (ctx->options & E2F_OPT_NO))
1077                 suppress++;
1078         if (!suppress) {
1079                 message = ptr->e2p_description;
1080                 if (ctx->options & E2F_OPT_PREEN) {
1081                         printf("%s: ", ctx->device_name);
1082 #if 0
1083                         if (ptr->e2p_preen_msg)
1084                                 message = ptr->e2p_preen_msg;
1085 #endif
1086                 }
1087                 print_e2fsck_message(ctx, message, pctx, 1);
1088         }
1089         if (!(ptr->flags & PR_PREEN_OK) && (ptr->prompt != PROMPT_NONE))
1090                 preenhalt(ctx);
1091
1092         if (ptr->flags & PR_FATAL)
1093                 fatal_error(ctx, 0);
1094
1095         if (ptr->prompt == PROMPT_NONE) {
1096                 if (ptr->flags & PR_NOCOLLATE)
1097                         answer = -1;
1098                 else
1099                         answer = def_yn;
1100         } else {
1101                 if (ctx->options & E2F_OPT_PREEN) {
1102                         answer = def_yn;
1103                         if (!(ptr->flags & PR_PREEN_NOMSG))
1104                                 print_answer = 1;
1105                 } else if ((ptr->flags & PR_LATCH_MASK) &&
1106                            (ldesc->flags & (PRL_YES | PRL_NO))) {
1107                         if (!suppress)
1108                                 print_answer = 1;
1109                         if (ldesc->flags & PRL_YES)
1110                                 answer = 1;
1111                         else
1112                                 answer = 0;
1113                 } else
1114                         answer = ask(ctx, prompt[(int) ptr->prompt], def_yn);
1115                 if (!answer && !(ptr->flags & PR_NO_OK))
1116                         ext2fs_unmark_valid(fs);
1117         
1118                 if (print_answer)
1119                         printf("%s.\n", answer ?
1120                                preen_msg[(int) ptr->prompt] : "IGNORED");
1121         
1122         }
1123
1124         if (ptr->flags & PR_AFTER_CODE)
1125                 (void) fix_problem(ctx, ptr->second_code, pctx);
1126
1127         if ((ptr->prompt == PROMPT_ABORT) && answer)
1128                 fatal_error(ctx, 0);
1129
1130         return answer;
1131 }