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