problem.c revision 521e36857227b21e7ab47b0a97f788d2af9f9717
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 22#define PROMPT_FIX 0 23#define PROMPT_CLEAR 1 24#define PROMPT_RELOCATE 2 25#define PROMPT_ALLOCATE 3 26#define PROMPT_EXPAND 4 27#define PROMPT_CONNECT 5 28#define PROMPT_CREATE 6 29#define PROMPT_SALVAGE 7 30#define PROMPT_TRUNCATE 8 31#define PROMPT_CLEAR_INODE 9 32 33/* 34 * These are the prompts which are used to ask the user if they want 35 * to fix a problem. 36 */ 37static const char *prompt[] = { 38 "Fix", /* 0 */ 39 "Clear", /* 1 */ 40 "Relocate", /* 2 */ 41 "Allocate", /* 3 */ 42 "Expand", /* 4 */ 43 "Connect to /lost+found", /* 5 */ 44 "Create", /* 6 */ 45 "Salvage", /* 7 */ 46 "Truncate", /* 8 */ 47 "Clear inode" /* 9 */ 48 }; 49 50/* 51 * These messages are printed when we are preen mode and we will be 52 * automatically fixing the problem. 53 */ 54static const char *preen_msg[] = { 55 "FIXED", /* 0 */ 56 "CLEARED", /* 1 */ 57 "RELOCATED", /* 2 */ 58 "ALLOCATED", /* 3 */ 59 "EXPANDED", /* 4 */ 60 "RECONNECTED", /* 5 */ 61 "CREATED", /* 6 */ 62 "SALVAGED", /* 7 */ 63 "TRUNCATED", /* 8 */ 64 "INODE CLEARED" /* 9 */ 65}; 66 67static struct e2fsck_problem problem_table[] = { 68 69 /* Pre-Pass 1 errors */ 70 71 /* Block bitmap not in group */ 72 { PR_0_BB_NOT_GROUP, "@b @B for @g %g is not in @g. (@b %b)\n", 73 PROMPT_RELOCATE, 0 }, 74 75 /* Inode bitmap not in group */ 76 { PR_0_IB_NOT_GROUP, "@i @B for @g %g is not in @g. (@b %b)\n", 77 PROMPT_RELOCATE, 0 }, 78 79 /* Inode table not in group */ 80 { PR_0_ITABLE_NOT_GROUP, 81 "@i table for @g %g is not in @g. (@b %b)\n" 82 "WARNING: SEVERE DATA LOSS POSSIBLE.\n", 83 PROMPT_RELOCATE, 0 }, 84 85 /* Pass 1 errors */ 86 87 /* Root directory is not an inode */ 88 { PR_1_ROOT_NO_DIR, "@r is not a @d. ", 89 PROMPT_CLEAR, 0 }, 90 91 /* Root directory has dtime set */ 92 { PR_1_ROOT_DTIME, 93 "@r has dtime set (probably due to old mke2fs). ", 94 PROMPT_FIX, PR_PREEN_OK }, 95 96 /* Reserved inode has bad mode */ 97 { PR_1_RESERVED_BAD_MODE, 98 "Reserved @i %i has bad mode. ", 99 PROMPT_CLEAR, PR_PREEN_OK }, 100 101 /* Deleted inode has zero dtime */ 102 { PR_1_ZERO_DTIME, 103 "@D @i %i has zero dtime. ", 104 PROMPT_FIX, PR_PREEN_OK }, 105 106 /* Inode in use, but dtime set */ 107 { PR_1_SET_DTIME, 108 "@i %i is in use, but has dtime set. ", 109 PROMPT_FIX, PR_PREEN_OK }, 110 111 /* Zero-length directory */ 112 { PR_1_ZERO_LENGTH_DIR, 113 "@i %i is a @z @d. ", 114 PROMPT_CLEAR, PR_PREEN_OK }, 115 116 /* Block bitmap conflicts with some other fs block */ 117 { PR_1_BB_CONFLICT, 118 "@g %N's @b @B at %b @C.\n", 119 PROMPT_RELOCATE, 0 }, 120 121 /* Inode bitmap conflicts with some other fs block */ 122 { PR_1_IB_CONFLICT, 123 "@g %N's @i @B at %b @C.\n", 124 PROMPT_RELOCATE, 0 }, 125 126 /* Inode table conflicts with some other fs block */ 127 { PR_1_ITABLE_CONFLICT, 128 "@g %g's @i table at %b @C.\n", 129 PROMPT_RELOCATE, 0 }, 130 131 /* Block bitmap is on a bad block */ 132 { PR_1_BB_BAD_BLOCK, 133 "@g %g's @b @B (%b) is bad. ", 134 PROMPT_RELOCATE, 0 }, 135 136 /* Inode bitmap is on a bad block */ 137 { PR_1_IB_BAD_BLOCK, 138 "@g %g's @i @B (%b) is bad. ", 139 PROMPT_RELOCATE, 0 }, 140 141 /* Inode has incorrect i_size */ 142 { PR_1_BAD_I_SIZE, 143 "@i %i, i_size is %Is, @s %N. ", 144 PROMPT_FIX, PR_PREEN_OK }, 145 146 /* Inode has incorrect i_blocks */ 147 { PR_1_BAD_I_BLOCKS, 148 "@i %i, i_blocks is %Ib, @s %N. ", 149 PROMPT_FIX, PR_PREEN_OK }, 150 151 /* Illegal block number in inode */ 152 { PR_1_ILLEGAL_BLOCK_NUM, 153 "Illegal @b #%B (%b) in @i %i. ", 154 PROMPT_CLEAR, PR_LATCH_BLOCK }, 155 156 /* Block number overlaps fs metadata */ 157 { PR_1_BLOCK_OVERLAPS_METADATA, 158 "@b #%B (%b) overlaps filesystem metadata in @i %i. ", 159 PROMPT_CLEAR, PR_LATCH_BLOCK }, 160 161 /* Inode has illegal blocks (latch question) */ 162 { PR_1_INODE_BLOCK_LATCH, 163 "@i %i has illegal @b(s). ", 164 PROMPT_CLEAR, 0 }, 165 166 /* Too many bad blocks in inode */ 167 { PR_1_TOO_MANY_BAD_BLOCKS, 168 "Too many illegal @bs in @i %i.\n", 169 PROMPT_CLEAR_INODE, PR_NO_OK }, 170 171 /* Illegal block number in bad block inode */ 172 { PR_1_BB_ILLEGAL_BLOCK_NUM, 173 "Illegal @b #%B (%b) in bad @b @i. ", 174 PROMPT_CLEAR, PR_LATCH_BBLOCK }, 175 176 /* Bad block inode has illegal blocks (latch question) */ 177 { PR_1_INODE_BBLOCK_LATCH, 178 "Bad @b @i has illegal @b(s). ", 179 PROMPT_CLEAR, 0 }, 180 181 /* Pass 1b errors */ 182 183 /* File has duplicate blocks */ 184 { PR_1B_DUP_FILE, 185 "File %Q (@i #%i, mod time %IM) \n" 186 " has %B duplicate @b(s), shared with %N file(s):\n", 187 PROMPT_FIX, PR_MSG_ONLY }, 188 189 /* List of files sharing duplicate blocks */ 190 { PR_1B_DUP_FILE_LIST, 191 "\t%Q (@i #%i, mod time %IM)\n", 192 PROMPT_FIX, PR_MSG_ONLY }, 193 194 /* File sharing blocks with filesystem metadata */ 195 { PR_1B_SHARE_METADATA, 196 "\t<filesystem metadata>\n", 197 PROMPT_FIX, PR_MSG_ONLY }, 198 199 /* Pass 2 errors */ 200 201 /* Bad inode number for '.' */ 202 { PR_2_BAD_INODE_DOT, 203 "Bad @i number for '.' in @d @i %i.\n", 204 PROMPT_FIX, 0 }, 205 206 /* Directory entry has bad inode number */ 207 { PR_2_BAD_INO, 208 "@E has bad @i #: %Di.\n", 209 PROMPT_CLEAR, 0 }, 210 211 /* Directory entry has deleted or unused inode */ 212 { PR_2_UNUSED_INODE, 213 "@E has @D/unused @i %Di. ", 214 PROMPT_CLEAR, PR_PREEN_OK }, 215 216 /* Directry entry is link to '.' */ 217 { PR_2_LINK_DOT, 218 "@E @L to '.' ", 219 PROMPT_CLEAR, 0 }, 220 221 /* Directory entry points to inode now located in a bad block */ 222 { PR_2_BB_INODE, 223 "@E points to @i (%Di) located in a bad @b.\n", 224 PROMPT_CLEAR, 0 }, 225 226 /* Directory entry contains a link to a directory */ 227 { PR_2_LINK_DIR, 228 "@E @L to @d %P (%Di).\n", 229 PROMPT_CLEAR, 0 }, 230 231 /* Directory entry contains a link to the root directry */ 232 { PR_2_LINK_ROOT, 233 "@E @L to the @r.\n", 234 PROMPT_CLEAR, 0 }, 235 236 /* Directory entry has illegal characters in its name */ 237 { PR_2_BAD_NAME, 238 "@E has illegal characters in its name.\n", 239 PROMPT_FIX, 0 }, 240 241 /* Missing '.' in directory inode */ 242 { PR_2_MISSING_DOT, 243 "Missing '.' in @d @i %i.\n", 244 PROMPT_FIX, 0 }, 245 246 /* Missing '..' in directory inode */ 247 { PR_2_MISSING_DOT_DOT, 248 "Missing '..' in @d @i %i.\n", 249 PROMPT_FIX, 0 }, 250 251 /* First entry in directory inode doesn't contain '.' */ 252 { PR_2_1ST_NOT_DOT, 253 "First @e '%Dn' (inode=%Di) in @d @i %i (%p) @s '.'\n", 254 PROMPT_FIX, 0 }, 255 256 /* Second entry in directory inode doesn't contain '..' */ 257 { PR_2_2ND_NOT_DOT_DOT, 258 "Second @e '%Dn' (inode=%Di) in @d @i %i @s '..'\n", 259 PROMPT_FIX, 0 }, 260 261 /* i_faddr should be zero */ 262 { PR_2_FADDR_ZERO, 263 "i_faddr @F %IF, @s zero.\n", 264 PROMPT_CLEAR, 0 }, 265 266 /* i_file_acl should be zero */ 267 { PR_2_FILE_ACL_ZERO, 268 "i_file_acl @F %If, @s zero.\n", 269 PROMPT_CLEAR, 0 }, 270 271 /* i_dir_acl should be zero */ 272 { PR_2_DIR_ACL_ZERO, 273 "i_dir_acl @F %Id, @s zero.\n", 274 PROMPT_CLEAR, 0 }, 275 276 /* i_frag should be zero */ 277 { PR_2_FRAG_ZERO, 278 "i_frag @F %N, @s zero.\n", 279 PROMPT_CLEAR, 0 }, 280 281 /* i_fsize should be zero */ 282 { PR_2_FSIZE_ZERO, 283 "i_fsize @F %N, @s zero.\n", 284 PROMPT_CLEAR, 0 }, 285 286 /* inode has bad mode */ 287 { PR_2_BAD_MODE, 288 "@i %i (%Q) has a bad mode (%Im).\n", 289 PROMPT_CLEAR, 0 }, 290 291 /* directory corrupted */ 292 { PR_2_DIR_CORRUPTED, 293 "@d @i %i, @b %B, offset %N: @d corrupted\n", 294 PROMPT_SALVAGE, 0 }, 295 296 /* filename too long */ 297 { PR_2_FILENAME_LONG, 298 "@d @i %i, @b %B, offset %N: filename too long\n", 299 PROMPT_TRUNCATE, 0 }, 300 301 /* Directory inode has a missing block (hole) */ 302 { PR_2_DIRECTORY_HOLE, 303 "@d @i %i has an unallocated @b #%B. ", 304 PROMPT_ALLOCATE, 0 }, 305 306 /* '.' is not NULL terminated */ 307 { PR_2_DOT_NULL_TERM, 308 "'.' directory entry in @d @i %i is not NULL terminated\n", 309 PROMPT_FIX, 0 }, 310 311 /* '..' is not NULL terminated */ 312 { PR_2_DOT_DOT_NULL_TERM, 313 "'..' directory entry in @d @i %i is not NULL terminated\n", 314 PROMPT_FIX, 0 }, 315 316 /* Pass 3 errors */ 317 318 /* Root inode not allocated */ 319 { PR_3_NO_ROOT_INODE, 320 "@r not allocated. ", 321 PROMPT_ALLOCATE, 0 }, 322 323 /* No room in lost+found */ 324 { PR_3_EXPAND_LF_DIR, 325 "No room in @l @d. ", 326 PROMPT_EXPAND, 0 }, 327 328 /* Unconnected directory inode */ 329 { PR_3_UNCONNECTED_DIR, 330 "Unconnected @d @i %i (%p)\n", 331 PROMPT_CONNECT, 0 }, 332 333 /* /lost+found not found */ 334 { PR_3_NO_LF_DIR, 335 "/@l not found. ", 336 PROMPT_CREATE, 0 }, 337 338 /* .. entry is incorrect */ 339 { PR_3_BAD_DOT_DOT, 340 "'..' in %Q (%i) is %P (%j), @s %q (%d).\n", 341 PROMPT_FIX, 0 }, 342 343 /* Pass 4 errors */ 344 345 /* Unattached zero-length inode */ 346 { PR_4_ZERO_LEN_INODE, 347 "@u @z @i %i. ", 348 PROMPT_CLEAR, PR_PREEN_OK|PR_NO_OK }, 349 350 /* Unattached inode */ 351 { PR_4_UNATTACHED_INODE, 352 "@u @i %i\n", 353 PROMPT_CONNECT, 0 }, 354 355 /* Inode ref count wrong */ 356 { PR_4_BAD_REF_COUNT, 357 "@i %i ref count is %Il, @s %N. ", 358 PROMPT_FIX, PR_PREEN_OK }, 359 360 { 0 } 361}; 362 363/* 364 * This is the latch flags register. It allows several problems to be 365 * "latched" together. This means that the user has to answer but one 366 * question for the set of problems, and all of the associated 367 * problems will be either fixed or not fixed. 368 */ 369char pr_latch[7]; /* Latch flags register */ 370char pr_suppress[7]; /* Latch groups which are suppressed */ 371int latch_question[7] = { 372 PR_1_INODE_BLOCK_LATCH, 373 PR_1_INODE_BBLOCK_LATCH 374}; 375 376static struct e2fsck_problem *find_problem(int code) 377{ 378 int i; 379 380 for (i=0; problem_table[i].e2p_code; i++) { 381 if (problem_table[i].e2p_code == code) 382 return &problem_table[i]; 383 } 384 return 0; 385} 386 387void reset_problem_latch(int mask) 388{ 389 pr_latch[PR_LATCH(mask)] = 0; 390 pr_suppress[PR_LATCH(mask)] = 0; 391} 392 393void suppress_latch_group(int mask, int value) 394{ 395 pr_suppress[PR_LATCH(mask)] = value; 396} 397 398void clear_problem_context(struct problem_context *ctx) 399{ 400 memset(ctx, 0, sizeof(struct problem_context)); 401 ctx->blkcount = -1; 402 ctx->group = -1; 403} 404 405int fix_problem(ext2_filsys fs, int code, struct problem_context *ctx) 406{ 407 struct e2fsck_problem *ptr; 408 int def_yn, answer; 409 int latch; 410 int print_answer = 0; 411 int suppress = 0; 412 413 ptr = find_problem(code); 414 if (!ptr) { 415 printf("Unhandled error code (%d)!\n", code); 416 return 0; 417 } 418 def_yn = (ptr->flags & PR_NO_DEFAULT) ? 0 : 1; 419 420 /* 421 * Do special latch processing. This is where we ask the 422 * latch question, if it exists 423 */ 424 if (ptr->flags & PR_LATCH_MASK) { 425 latch = PR_LATCH(ptr->flags); 426 if (latch_question[latch] && !pr_latch[latch]) 427 pr_latch[latch] = fix_problem(fs, 428 latch_question[latch], 429 ctx) + 1; 430 if (pr_suppress[latch]) 431 suppress++; 432 } 433 434 if (!suppress) { 435 if (preen) 436 printf("%s: ", device_name); 437 print_e2fsck_message(fs, ptr->e2p_description, ctx, 1); 438 } 439 if (!(ptr->flags & PR_PREEN_OK)) 440 preenhalt(fs); 441 442 if (ptr->flags & PR_MSG_ONLY) 443 return 1; 444 445 if (preen) { 446 answer = def_yn; 447 print_answer = 1; 448 } else if (ptr->flags & PR_LATCH_MASK) { 449 latch = PR_LATCH(ptr->flags); 450 if (!pr_latch[latch]) 451 pr_latch[latch] = 452 ask(prompt[(int) ptr->prompt], def_yn) + 1; 453 else 454 print_answer = 1; 455 answer = pr_latch[latch] - 1; 456 } else 457 answer = ask(prompt[(int) ptr->prompt], def_yn); 458 if (!answer && !(ptr->flags & PR_NO_OK)) 459 ext2fs_unmark_valid(fs); 460 461 if (print_answer) 462 printf("%s.\n", 463 answer ? preen_msg[(int) ptr->prompt] : "IGNORED"); 464 465 return answer; 466} 467