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