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