message.c revision ecf1b7767e1772f4c6dba8f02026057ed05397bd
1/* 2 * message.c --- print e2fsck messages (with compression) 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 * print_e2fsck_message() prints a message to the user, using 12 * compression techniques and expansions of abbreviations. 13 * 14 * The following % expansions are supported: 15 * 16 * %b <blk> block number 17 * %B <blkcount> integer 18 * %c <blk2> block number 19 * %di <dirent>->ino inode number 20 * %dn <dirent>->name string 21 * %dr <dirent>->rec_len 22 * %dl <dirent>->name_len 23 * %dt <dirent>->filetype 24 * %D <dir> inode number 25 * %g <group> integer 26 * %i <ino> inode number 27 * %Is <inode> -> i_size 28 * %Ib <inode> -> i_blocks 29 * %Il <inode> -> i_links_count 30 * %Im <inode> -> i_mode 31 * %IM <inode> -> i_mtime 32 * %IF <inode> -> i_faddr 33 * %If <inode> -> i_file_acl 34 * %Id <inode> -> i_dir_acl 35 * %Iu <inode> -> i_uid 36 * %Ig <inode> -> i_gid 37 * %j <ino2> inode number 38 * %m <com_err error message> 39 * %N <num> 40 * %p ext2fs_get_pathname of directory <ino> 41 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as 42 * the containing directory. (If dirent is NULL 43 * then return the pathname of directory <ino2>) 44 * %q ext2fs_get_pathname of directory <dir> 45 * %Q ext2fs_get_pathname of directory <ino> with <dir> as 46 * the containing directory. 47 * %s <str> miscellaneous string 48 * %S backup superblock 49 * %X <num> hexadecimal format 50 * 51 * The following '@' expansions are supported: 52 * 53 * @A error allocating 54 * @b block 55 * @B bitmap 56 * @c compress 57 * @C conflicts with some other fs block 58 * @i inode 59 * @I illegal 60 * @D deleted 61 * @d directory 62 * @e entry 63 * @E Entry '%Dn' in %p (%i) 64 * @f filesystem 65 * @F for @i %i (%Q) is 66 * @g group 67 * @l lost+found 68 * @L is a link 69 * @o orphaned 70 * @r root inode 71 * @s should be 72 * @S superblock 73 * @u unattached 74 * @z zero-length 75 */ 76 77#include <stdlib.h> 78#include <unistd.h> 79#include <string.h> 80#include <ctype.h> 81#include <termios.h> 82 83#include "e2fsck.h" 84 85#include "problem.h" 86 87#ifdef __GNUC__ 88#define _INLINE_ __inline__ 89#else 90#define _INLINE_ 91#endif 92 93/* 94 * This structure defines the abbreviations used by the text strings 95 * below. The first character in the string is the index letter. An 96 * abbreviation of the form '@<i>' is expanded by looking up the index 97 * letter <i> in the table below. 98 */ 99static const char *abbrevs[] = { 100 N_("Aerror allocating"), 101 N_("bblock"), 102 N_("Bbitmap"), 103 N_("ccompress"), 104 N_("Cconflicts with some other fs @b"), 105 N_("iinode"), 106 N_("Iillegal"), 107 N_("Ddeleted"), 108 N_("ddirectory"), 109 N_("eentry"), 110 N_("E@e '%Dn' in %p (%i)"), 111 N_("ffilesystem"), 112 N_("Ffor @i %i (%Q) is"), 113 N_("ggroup"), 114 N_("llost+found"), 115 N_("Lis a link"), 116 N_("oorphaned"), 117 N_("rroot @i"), 118 N_("sshould be"), 119 N_("Ssuper@b"), 120 N_("uunattached"), 121 N_("zzero-length"), 122 "@@", 123 0 124 }; 125 126/* 127 * Give more user friendly names to the "special" inodes. 128 */ 129#define num_special_inodes 7 130static const char *special_inode_name[] = 131{ 132 N_("<The NULL inode>"), /* 0 */ 133 N_("<The bad blocks inode>"), /* 1 */ 134 "/", /* 2 */ 135 N_("<The ACL index inode>"), /* 3 */ 136 N_("<The ACL data inode>"), /* 4 */ 137 N_("<The boot loader inode>"), /* 5 */ 138 N_("<The undelete directory inode>") /* 6 */ 139}; 140 141/* 142 * This function does "safe" printing. It will convert non-printable 143 * ASCII characters using '^' and M- notation. 144 */ 145static void safe_print(const char *cp, int len) 146{ 147 unsigned char ch; 148 149 if (len < 0) 150 len = strlen(cp); 151 152 while (len--) { 153 ch = *cp++; 154 if (ch > 128) { 155 fputs("M-", stdout); 156 ch -= 128; 157 } 158 if ((ch < 32) || (ch == 0x7f)) { 159 fputc('^', stdout); 160 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */ 161 } 162 fputc(ch, stdout); 163 } 164} 165 166 167/* 168 * This function prints a pathname, using the ext2fs_get_pathname 169 * function 170 */ 171static void print_pathname(ext2_filsys fs, ino_t dir, ino_t ino) 172{ 173 errcode_t retval; 174 char *path; 175 176 if (!dir && (ino < num_special_inodes)) { 177 fputs(_(special_inode_name[ino]), stdout); 178 return; 179 } 180 181 retval = ext2fs_get_pathname(fs, dir, ino, &path); 182 if (retval) 183 fputs("???", stdout); 184 else { 185 safe_print(path, -1); 186 ext2fs_free_mem((void **) &path); 187 } 188} 189 190/* 191 * This function handles the '@' expansion. We allow recursive 192 * expansion; an @ expression can contain further '@' and '%' 193 * expressions. 194 */ 195static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch, 196 struct problem_context *pctx, 197 int *first) 198{ 199 const char **cpp, *str; 200 201 /* Search for the abbreviation */ 202 for (cpp = abbrevs; *cpp; cpp++) { 203 if (ch == *cpp[0]) 204 break; 205 } 206 if (*cpp) { 207 str = (*cpp) + 1; 208 if (*first && islower(*str)) { 209 *first = 0; 210 fputc(toupper(*str++), stdout); 211 } 212 print_e2fsck_message(ctx, _(str), pctx, *first); 213 } else 214 printf("@%c", ch); 215} 216 217/* 218 * This function expands '%IX' expressions 219 */ 220static _INLINE_ void expand_inode_expression(char ch, 221 struct problem_context *ctx) 222{ 223 struct ext2_inode *inode; 224 char * time_str; 225 time_t t; 226 227 if (!ctx || !ctx->inode) 228 goto no_inode; 229 230 inode = ctx->inode; 231 232 switch (ch) { 233 case 's': 234 if (LINUX_S_ISDIR(inode->i_mode)) 235 printf("%u", inode->i_size); 236 else { 237#ifdef EXT2_NO_64_TYPE 238 if (inode->i_size_high) 239 printf("0x%x%08x", inode->i_size_high, 240 inode->i_size); 241 else 242 printf("%u", inode->i_size); 243#else 244 printf("%llu", (inode->i_size | 245 ((__u64) inode->i_size_high << 32))); 246#endif 247 } 248 break; 249 case 'b': 250 printf("%u", inode->i_blocks); 251 break; 252 case 'l': 253 printf("%d", inode->i_links_count); 254 break; 255 case 'm': 256 printf("0%o", inode->i_mode); 257 break; 258 case 'M': 259 t = inode->i_mtime; 260 time_str = ctime(&t); 261 printf("%.24s", time_str); 262 break; 263 case 'F': 264 printf("%u", inode->i_faddr); 265 break; 266 case 'f': 267 printf("%u", inode->i_file_acl); 268 break; 269 case 'd': 270 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ? 271 inode->i_dir_acl : 0)); 272 break; 273 case 'u': 274 printf("%d", (inode->i_uid | 275 (inode->osd2.linux2.l_i_uid_high << 16))); 276 break; 277 case 'g': 278 printf("%d", (inode->i_gid | 279 (inode->osd2.linux2.l_i_gid_high << 16))); 280 break; 281 default: 282 no_inode: 283 printf("%%I%c", ch); 284 break; 285 } 286} 287 288/* 289 * This function expands '%dX' expressions 290 */ 291static _INLINE_ void expand_dirent_expression(char ch, 292 struct problem_context *ctx) 293{ 294 struct ext2_dir_entry *dirent; 295 int len; 296 297 if (!ctx || !ctx->dirent) 298 goto no_dirent; 299 300 dirent = ctx->dirent; 301 302 switch (ch) { 303 case 'i': 304 printf("%u", dirent->inode); 305 break; 306 case 'n': 307 len = dirent->name_len & 0xFF; 308 if (len > EXT2_NAME_LEN) 309 len = EXT2_NAME_LEN; 310 if (len > dirent->rec_len) 311 len = dirent->rec_len; 312 safe_print(dirent->name, len); 313 break; 314 case 'r': 315 printf("%u", dirent->rec_len); 316 break; 317 case 'l': 318 printf("%u", dirent->name_len & 0xFF); 319 break; 320 case 't': 321 printf("%u", dirent->name_len >> 8); 322 break; 323 default: 324 no_dirent: 325 printf("%%D%c", ch); 326 break; 327 } 328} 329 330static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch, 331 struct problem_context *ctx) 332{ 333 if (!ctx) 334 goto no_context; 335 336 switch (ch) { 337 case '%': 338 fputc('%', stdout); 339 break; 340 case 'b': 341 printf("%u", ctx->blk); 342 break; 343 case 'B': 344#ifdef EXT2_NO_64_TYPE 345 printf("%d", ctx->blkcount); 346#else 347 printf("%lld", ctx->blkcount); 348#endif 349 break; 350 case 'c': 351 printf("%u", ctx->blk2); 352 break; 353 case 'd': 354 printf("%lu", ctx->dir); 355 break; 356 case 'g': 357 printf("%d", ctx->group); 358 break; 359 case 'i': 360 printf("%lu", ctx->ino); 361 break; 362 case 'j': 363 printf("%lu", ctx->ino2); 364 break; 365 case 'm': 366 printf("%s", error_message(ctx->errcode)); 367 break; 368 case 'N': 369#ifdef EXT2_NO_64_TYPE 370 printf("%u", ctx->num); 371#else 372 printf("%llu", ctx->num); 373#endif 374 break; 375 case 'p': 376 print_pathname(fs, ctx->ino, 0); 377 break; 378 case 'P': 379 print_pathname(fs, ctx->ino2, 380 ctx->dirent ? ctx->dirent->inode : 0); 381 break; 382 case 'q': 383 print_pathname(fs, ctx->dir, 0); 384 break; 385 case 'Q': 386 print_pathname(fs, ctx->dir, ctx->ino); 387 break; 388 case 'S': 389 printf("%d", get_backup_sb(fs)); 390 break; 391 case 's': 392 printf("%s", ctx->str); 393 break; 394 case 'X': 395#ifdef EXT2_NO_64_TYPE 396 printf("0x%x", ctx->num); 397#else 398 printf("0x%llx", ctx->num); 399#endif 400 break; 401 default: 402 no_context: 403 printf("%%%c", ch); 404 break; 405 } 406} 407 408void print_e2fsck_message(e2fsck_t ctx, const char *msg, 409 struct problem_context *pctx, int first) 410{ 411 ext2_filsys fs = ctx->fs; 412 const char * cp; 413 int i; 414 415 e2fsck_clear_progbar(ctx); 416 for (cp = msg; *cp; cp++) { 417 if (cp[0] == '@') { 418 cp++; 419 expand_at_expression(ctx, *cp, pctx, &first); 420 } else if (cp[0] == '%' && cp[1] == 'I') { 421 cp += 2; 422 expand_inode_expression(*cp, pctx); 423 } else if (cp[0] == '%' && cp[1] == 'D') { 424 cp += 2; 425 expand_dirent_expression(*cp, pctx); 426 } else if ((cp[0] == '%')) { 427 cp++; 428 expand_percent_expression(fs, *cp, pctx); 429 } else { 430 for (i=0; cp[i]; i++) 431 if ((cp[i] == '@') || cp[i] == '%') 432 break; 433 printf("%.*s", i, cp); 434 cp += i-1; 435 } 436 first = 0; 437 } 438} 439