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