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