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