blob: 26a7c023bb38b2e81b9a9a4a830896a040e6265b [file] [log] [blame]
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001/*
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
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000018 * %c <blk2> block number
Theodore Ts'o21c84b71997-04-29 16:15:03 +000019 * %di <dirent>->ino inode number
20 * %dn <dirent>->name string
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000021 * %dr <dirent>->rec_len
22 * %dl <dirent>->name_len
Theodore Ts'oaa4115a1999-10-21 19:33:18 +000023 * %dt <dirent>->filetype
Theodore Ts'o21c84b71997-04-29 16:15:03 +000024 * %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
Theodore Ts'oecf1b772000-08-20 22:06:31 +000035 * %Iu <inode> -> i_uid
36 * %Ig <inode> -> i_gid
Theodore Ts'o21c84b71997-04-29 16:15:03 +000037 * %j <ino2> inode number
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000038 * %m <com_err error message>
Theodore Ts'o21c84b71997-04-29 16:15:03 +000039 * %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.
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000047 * %s <str> miscellaneous string
48 * %S backup superblock
Theodore Ts'o3b5386d2000-08-14 14:25:19 +000049 * %X <num> hexadecimal format
Theodore Ts'o21c84b71997-04-29 16:15:03 +000050 *
51 * The following '@' expansions are supported:
52 *
Theodore Ts'of8188ff1997-11-14 05:23:04 +000053 * @A error allocating
Theodore Ts'o21c84b71997-04-29 16:15:03 +000054 * @b block
55 * @B bitmap
Theodore Ts'o19178752000-02-11 15:55:07 +000056 * @c compress
Theodore Ts'o21c84b71997-04-29 16:15:03 +000057 * @C conflicts with some other fs block
Theodore Ts'o21c84b71997-04-29 16:15:03 +000058 * @D deleted
59 * @d directory
60 * @e entry
61 * @E Entry '%Dn' in %p (%i)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000062 * @f filesystem
Theodore Ts'o21c84b71997-04-29 16:15:03 +000063 * @F for @i %i (%Q) is
64 * @g group
Theodore Ts'od74edf42001-01-03 19:38:04 +000065 * @i inode
66 * @I illegal
67 * @j journal
Theodore Ts'o21c84b71997-04-29 16:15:03 +000068 * @l lost+found
69 * @L is a link
Theodore Ts'o80bfaa32000-08-18 15:08:37 +000070 * @o orphaned
Theodore Ts'o21c84b71997-04-29 16:15:03 +000071 * @r root inode
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000072 * @s should be
73 * @S superblock
Theodore Ts'o80bfaa32000-08-18 15:08:37 +000074 * @u unattached
Theodore Ts'od74edf42001-01-03 19:38:04 +000075 * @v device
Theodore Ts'o21c84b71997-04-29 16:15:03 +000076 * @z zero-length
77 */
78
79#include <stdlib.h>
80#include <unistd.h>
81#include <string.h>
82#include <ctype.h>
83#include <termios.h>
84
85#include "e2fsck.h"
86
87#include "problem.h"
88
89#ifdef __GNUC__
90#define _INLINE_ __inline__
91#else
92#define _INLINE_
93#endif
94
95/*
96 * This structure defines the abbreviations used by the text strings
97 * below. The first character in the string is the index letter. An
98 * abbreviation of the form '@<i>' is expanded by looking up the index
99 * letter <i> in the table below.
100 */
101static const char *abbrevs[] = {
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000102 N_("Aerror allocating"),
103 N_("bblock"),
104 N_("Bbitmap"),
Theodore Ts'o19178752000-02-11 15:55:07 +0000105 N_("ccompress"),
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000106 N_("Cconflicts with some other fs @b"),
107 N_("iinode"),
108 N_("Iillegal"),
Theodore Ts'o1ce64532001-01-03 15:34:20 +0000109 N_("jjournal"),
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000110 N_("Ddeleted"),
111 N_("ddirectory"),
112 N_("eentry"),
113 N_("E@e '%Dn' in %p (%i)"),
114 N_("ffilesystem"),
115 N_("Ffor @i %i (%Q) is"),
116 N_("ggroup"),
117 N_("llost+found"),
118 N_("Lis a link"),
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000119 N_("oorphaned"),
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000120 N_("rroot @i"),
121 N_("sshould be"),
122 N_("Ssuper@b"),
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000123 N_("uunattached"),
Theodore Ts'od74edf42001-01-03 19:38:04 +0000124 N_("vdevice"),
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000125 N_("zzero-length"),
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000126 "@@",
127 0
128 };
129
130/*
131 * Give more user friendly names to the "special" inodes.
132 */
Theodore Ts'o721edd02001-01-12 21:05:57 +0000133#define num_special_inodes 11
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000134static const char *special_inode_name[] =
135{
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000136 N_("<The NULL inode>"), /* 0 */
137 N_("<The bad blocks inode>"), /* 1 */
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000138 "/", /* 2 */
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000139 N_("<The ACL index inode>"), /* 3 */
140 N_("<The ACL data inode>"), /* 4 */
141 N_("<The boot loader inode>"), /* 5 */
Theodore Ts'o721edd02001-01-12 21:05:57 +0000142 N_("<The undelete directory inode>"), /* 6 */
143 N_("<The group descriptor inode>"), /* 7 */
144 N_("<The journal inode>"), /* 8 */
145 N_("<Reserved inode 9>"), /* 9 */
146 N_("<Reserved inode 10>"), /* 10 */
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000147};
148
149/*
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000150 * This function does "safe" printing. It will convert non-printable
151 * ASCII characters using '^' and M- notation.
152 */
Theodore Ts'of68aa411999-10-26 14:20:22 +0000153static void safe_print(const char *cp, int len)
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000154{
155 unsigned char ch;
156
157 if (len < 0)
158 len = strlen(cp);
159
160 while (len--) {
161 ch = *cp++;
162 if (ch > 128) {
163 fputs("M-", stdout);
164 ch -= 128;
165 }
Theodore Ts'oec8d2c31999-11-19 18:52:36 +0000166 if ((ch < 32) || (ch == 0x7f)) {
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000167 fputc('^', stdout);
Theodore Ts'oec8d2c31999-11-19 18:52:36 +0000168 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000169 }
170 fputc(ch, stdout);
171 }
172}
173
174
175/*
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000176 * This function prints a pathname, using the ext2fs_get_pathname
177 * function
178 */
Theodore Ts'o86c627e2001-01-11 15:12:14 +0000179static void print_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000180{
181 errcode_t retval;
182 char *path;
183
184 if (!dir && (ino < num_special_inodes)) {
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000185 fputs(_(special_inode_name[ino]), stdout);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000186 return;
187 }
188
189 retval = ext2fs_get_pathname(fs, dir, ino, &path);
190 if (retval)
191 fputs("???", stdout);
192 else {
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000193 safe_print(path, -1);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000194 ext2fs_free_mem((void **) &path);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000195 }
196}
197
198/*
199 * This function handles the '@' expansion. We allow recursive
200 * expansion; an @ expression can contain further '@' and '%'
201 * expressions.
202 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000203static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
204 struct problem_context *pctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000205 int *first)
206{
207 const char **cpp, *str;
208
209 /* Search for the abbreviation */
210 for (cpp = abbrevs; *cpp; cpp++) {
211 if (ch == *cpp[0])
212 break;
213 }
214 if (*cpp) {
215 str = (*cpp) + 1;
216 if (*first && islower(*str)) {
217 *first = 0;
218 fputc(toupper(*str++), stdout);
219 }
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000220 print_e2fsck_message(ctx, _(str), pctx, *first);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000221 } else
222 printf("@%c", ch);
223}
224
225/*
Theodore Ts'oecf1b772000-08-20 22:06:31 +0000226 * This function expands '%IX' expressions
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000227 */
228static _INLINE_ void expand_inode_expression(char ch,
229 struct problem_context *ctx)
230{
231 struct ext2_inode *inode;
232 char * time_str;
233 time_t t;
234
235 if (!ctx || !ctx->inode)
236 goto no_inode;
237
238 inode = ctx->inode;
239
240 switch (ch) {
241 case 's':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000242 if (LINUX_S_ISDIR(inode->i_mode))
243 printf("%u", inode->i_size);
244 else {
245#ifdef EXT2_NO_64_TYPE
246 if (inode->i_size_high)
247 printf("0x%x%08x", inode->i_size_high,
248 inode->i_size);
249 else
250 printf("%u", inode->i_size);
251#else
252 printf("%llu", (inode->i_size |
253 ((__u64) inode->i_size_high << 32)));
254#endif
255 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000256 break;
257 case 'b':
258 printf("%u", inode->i_blocks);
259 break;
260 case 'l':
261 printf("%d", inode->i_links_count);
262 break;
263 case 'm':
264 printf("0%o", inode->i_mode);
265 break;
266 case 'M':
267 t = inode->i_mtime;
268 time_str = ctime(&t);
269 printf("%.24s", time_str);
270 break;
271 case 'F':
272 printf("%u", inode->i_faddr);
273 break;
274 case 'f':
275 printf("%u", inode->i_file_acl);
276 break;
277 case 'd':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000278 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
279 inode->i_dir_acl : 0));
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000280 break;
Theodore Ts'oecf1b772000-08-20 22:06:31 +0000281 case 'u':
282 printf("%d", (inode->i_uid |
283 (inode->osd2.linux2.l_i_uid_high << 16)));
284 break;
285 case 'g':
286 printf("%d", (inode->i_gid |
287 (inode->osd2.linux2.l_i_gid_high << 16)));
288 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000289 default:
290 no_inode:
291 printf("%%I%c", ch);
292 break;
293 }
294}
295
296/*
297 * This function expands '%dX' expressions
298 */
299static _INLINE_ void expand_dirent_expression(char ch,
300 struct problem_context *ctx)
301{
302 struct ext2_dir_entry *dirent;
303 int len;
304
305 if (!ctx || !ctx->dirent)
306 goto no_dirent;
307
308 dirent = ctx->dirent;
309
310 switch (ch) {
311 case 'i':
312 printf("%u", dirent->inode);
313 break;
314 case 'n':
Theodore Ts'ob6f79831998-03-09 13:10:37 +0000315 len = dirent->name_len & 0xFF;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000316 if (len > EXT2_NAME_LEN)
317 len = EXT2_NAME_LEN;
318 if (len > dirent->rec_len)
319 len = dirent->rec_len;
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000320 safe_print(dirent->name, len);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000321 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000322 case 'r':
323 printf("%u", dirent->rec_len);
324 break;
325 case 'l':
Theodore Ts'ob6f79831998-03-09 13:10:37 +0000326 printf("%u", dirent->name_len & 0xFF);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000327 break;
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000328 case 't':
329 printf("%u", dirent->name_len >> 8);
330 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000331 default:
332 no_dirent:
333 printf("%%D%c", ch);
334 break;
335 }
336}
337
338static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
339 struct problem_context *ctx)
340{
341 if (!ctx)
342 goto no_context;
343
344 switch (ch) {
345 case '%':
346 fputc('%', stdout);
347 break;
348 case 'b':
349 printf("%u", ctx->blk);
350 break;
351 case 'B':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000352#ifdef EXT2_NO_64_TYPE
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000353 printf("%d", ctx->blkcount);
Theodore Ts'o246501c1998-03-24 16:22:38 +0000354#else
355 printf("%lld", ctx->blkcount);
356#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000357 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000358 case 'c':
359 printf("%u", ctx->blk2);
360 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000361 case 'd':
Theodore Ts'o86c627e2001-01-11 15:12:14 +0000362 printf("%u", ctx->dir);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000363 break;
364 case 'g':
365 printf("%d", ctx->group);
366 break;
367 case 'i':
Theodore Ts'o86c627e2001-01-11 15:12:14 +0000368 printf("%u", ctx->ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000369 break;
370 case 'j':
Theodore Ts'o86c627e2001-01-11 15:12:14 +0000371 printf("%u", ctx->ino2);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000372 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000373 case 'm':
374 printf("%s", error_message(ctx->errcode));
375 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000376 case 'N':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000377#ifdef EXT2_NO_64_TYPE
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000378 printf("%u", ctx->num);
Theodore Ts'o246501c1998-03-24 16:22:38 +0000379#else
380 printf("%llu", ctx->num);
381#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000382 break;
383 case 'p':
384 print_pathname(fs, ctx->ino, 0);
385 break;
386 case 'P':
387 print_pathname(fs, ctx->ino2,
388 ctx->dirent ? ctx->dirent->inode : 0);
389 break;
390 case 'q':
391 print_pathname(fs, ctx->dir, 0);
392 break;
393 case 'Q':
394 print_pathname(fs, ctx->dir, ctx->ino);
395 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000396 case 'S':
397 printf("%d", get_backup_sb(fs));
398 break;
399 case 's':
Theodore Ts'o133a56d2000-11-17 05:40:49 +0000400 printf("%s", ctx->str ? ctx->str : "NULL");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000401 break;
Theodore Ts'o3b5386d2000-08-14 14:25:19 +0000402 case 'X':
403#ifdef EXT2_NO_64_TYPE
404 printf("0x%x", ctx->num);
405#else
406 printf("0x%llx", ctx->num);
407#endif
408 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000409 default:
410 no_context:
411 printf("%%%c", ch);
412 break;
413 }
414}
415
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000416void print_e2fsck_message(e2fsck_t ctx, const char *msg,
417 struct problem_context *pctx, int first)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000418{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000419 ext2_filsys fs = ctx->fs;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000420 const char * cp;
421 int i;
Theodore Ts'o5596def1999-07-19 15:27:37 +0000422
423 e2fsck_clear_progbar(ctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000424 for (cp = msg; *cp; cp++) {
425 if (cp[0] == '@') {
426 cp++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000427 expand_at_expression(ctx, *cp, pctx, &first);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000428 } else if (cp[0] == '%' && cp[1] == 'I') {
429 cp += 2;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000430 expand_inode_expression(*cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000431 } else if (cp[0] == '%' && cp[1] == 'D') {
432 cp += 2;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000433 expand_dirent_expression(*cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000434 } else if ((cp[0] == '%')) {
435 cp++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000436 expand_percent_expression(fs, *cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000437 } else {
438 for (i=0; cp[i]; i++)
439 if ((cp[i] == '@') || cp[i] == '%')
440 break;
441 printf("%.*s", i, cp);
442 cp += i-1;
443 }
444 first = 0;
445 }
446}