blob: bace3c51d18ea778b9b030c02e040ae01899b0d5 [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
35 * %j <ino2> inode number
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000036 * %m <com_err error message>
Theodore Ts'o21c84b71997-04-29 16:15:03 +000037 * %N <num>
38 * %p ext2fs_get_pathname of directory <ino>
39 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
40 * the containing directory. (If dirent is NULL
41 * then return the pathname of directory <ino2>)
42 * %q ext2fs_get_pathname of directory <dir>
43 * %Q ext2fs_get_pathname of directory <ino> with <dir> as
44 * the containing directory.
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000045 * %s <str> miscellaneous string
46 * %S backup superblock
Theodore Ts'o21c84b71997-04-29 16:15:03 +000047 *
48 * The following '@' expansions are supported:
49 *
Theodore Ts'of8188ff1997-11-14 05:23:04 +000050 * @A error allocating
Theodore Ts'o21c84b71997-04-29 16:15:03 +000051 * @b block
52 * @B bitmap
53 * @C conflicts with some other fs block
54 * @i inode
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +000055 * @I illegal
Theodore Ts'o21c84b71997-04-29 16:15:03 +000056 * @D deleted
57 * @d directory
58 * @e entry
59 * @E Entry '%Dn' in %p (%i)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000060 * @f filesystem
Theodore Ts'o21c84b71997-04-29 16:15:03 +000061 * @F for @i %i (%Q) is
62 * @g group
63 * @l lost+found
64 * @L is a link
65 * @u unattached
66 * @r root inode
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000067 * @s should be
68 * @S superblock
Theodore Ts'o21c84b71997-04-29 16:15:03 +000069 * @z zero-length
70 */
71
72#include <stdlib.h>
73#include <unistd.h>
74#include <string.h>
75#include <ctype.h>
76#include <termios.h>
77
78#include "e2fsck.h"
79
80#include "problem.h"
81
82#ifdef __GNUC__
83#define _INLINE_ __inline__
84#else
85#define _INLINE_
86#endif
87
88/*
89 * This structure defines the abbreviations used by the text strings
90 * below. The first character in the string is the index letter. An
91 * abbreviation of the form '@<i>' is expanded by looking up the index
92 * letter <i> in the table below.
93 */
94static const char *abbrevs[] = {
Theodore Ts'o0c4a0722000-02-07 03:11:03 +000095 N_("Aerror allocating"),
96 N_("bblock"),
97 N_("Bbitmap"),
98 N_("Cconflicts with some other fs @b"),
99 N_("iinode"),
100 N_("Iillegal"),
101 N_("Ddeleted"),
102 N_("ddirectory"),
103 N_("eentry"),
104 N_("E@e '%Dn' in %p (%i)"),
105 N_("ffilesystem"),
106 N_("Ffor @i %i (%Q) is"),
107 N_("ggroup"),
108 N_("llost+found"),
109 N_("Lis a link"),
110 N_("uunattached"),
111 N_("rroot @i"),
112 N_("sshould be"),
113 N_("Ssuper@b"),
114 N_("zzero-length"),
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000115 "@@",
116 0
117 };
118
119/*
120 * Give more user friendly names to the "special" inodes.
121 */
122#define num_special_inodes 7
123static const char *special_inode_name[] =
124{
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000125 N_("<The NULL inode>"), /* 0 */
126 N_("<The bad blocks inode>"), /* 1 */
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000127 "/", /* 2 */
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000128 N_("<The ACL index inode>"), /* 3 */
129 N_("<The ACL data inode>"), /* 4 */
130 N_("<The boot loader inode>"), /* 5 */
131 N_("<The undelete directory inode>") /* 6 */
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000132};
133
134/*
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000135 * This function does "safe" printing. It will convert non-printable
136 * ASCII characters using '^' and M- notation.
137 */
Theodore Ts'of68aa411999-10-26 14:20:22 +0000138static void safe_print(const char *cp, int len)
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000139{
140 unsigned char ch;
141
142 if (len < 0)
143 len = strlen(cp);
144
145 while (len--) {
146 ch = *cp++;
147 if (ch > 128) {
148 fputs("M-", stdout);
149 ch -= 128;
150 }
Theodore Ts'oec8d2c31999-11-19 18:52:36 +0000151 if ((ch < 32) || (ch == 0x7f)) {
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000152 fputc('^', stdout);
Theodore Ts'oec8d2c31999-11-19 18:52:36 +0000153 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000154 }
155 fputc(ch, stdout);
156 }
157}
158
159
160/*
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000161 * This function prints a pathname, using the ext2fs_get_pathname
162 * function
163 */
164static void print_pathname(ext2_filsys fs, ino_t dir, ino_t ino)
165{
166 errcode_t retval;
167 char *path;
168
169 if (!dir && (ino < num_special_inodes)) {
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000170 fputs(_(special_inode_name[ino]), stdout);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000171 return;
172 }
173
174 retval = ext2fs_get_pathname(fs, dir, ino, &path);
175 if (retval)
176 fputs("???", stdout);
177 else {
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000178 safe_print(path, -1);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000179 ext2fs_free_mem((void **) &path);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000180 }
181}
182
183/*
184 * This function handles the '@' expansion. We allow recursive
185 * expansion; an @ expression can contain further '@' and '%'
186 * expressions.
187 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000188static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
189 struct problem_context *pctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000190 int *first)
191{
192 const char **cpp, *str;
193
194 /* Search for the abbreviation */
195 for (cpp = abbrevs; *cpp; cpp++) {
196 if (ch == *cpp[0])
197 break;
198 }
199 if (*cpp) {
200 str = (*cpp) + 1;
201 if (*first && islower(*str)) {
202 *first = 0;
203 fputc(toupper(*str++), stdout);
204 }
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000205 print_e2fsck_message(ctx, _(str), pctx, *first);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000206 } else
207 printf("@%c", ch);
208}
209
210/*
211 * This function expands '%kX' expressions
212 */
213static _INLINE_ void expand_inode_expression(char ch,
214 struct problem_context *ctx)
215{
216 struct ext2_inode *inode;
217 char * time_str;
218 time_t t;
219
220 if (!ctx || !ctx->inode)
221 goto no_inode;
222
223 inode = ctx->inode;
224
225 switch (ch) {
226 case 's':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000227 if (LINUX_S_ISDIR(inode->i_mode))
228 printf("%u", inode->i_size);
229 else {
230#ifdef EXT2_NO_64_TYPE
231 if (inode->i_size_high)
232 printf("0x%x%08x", inode->i_size_high,
233 inode->i_size);
234 else
235 printf("%u", inode->i_size);
236#else
237 printf("%llu", (inode->i_size |
238 ((__u64) inode->i_size_high << 32)));
239#endif
240 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000241 break;
242 case 'b':
243 printf("%u", inode->i_blocks);
244 break;
245 case 'l':
246 printf("%d", inode->i_links_count);
247 break;
248 case 'm':
249 printf("0%o", inode->i_mode);
250 break;
251 case 'M':
252 t = inode->i_mtime;
253 time_str = ctime(&t);
254 printf("%.24s", time_str);
255 break;
256 case 'F':
257 printf("%u", inode->i_faddr);
258 break;
259 case 'f':
260 printf("%u", inode->i_file_acl);
261 break;
262 case 'd':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000263 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
264 inode->i_dir_acl : 0));
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000265 break;
266 default:
267 no_inode:
268 printf("%%I%c", ch);
269 break;
270 }
271}
272
273/*
274 * This function expands '%dX' expressions
275 */
276static _INLINE_ void expand_dirent_expression(char ch,
277 struct problem_context *ctx)
278{
279 struct ext2_dir_entry *dirent;
280 int len;
281
282 if (!ctx || !ctx->dirent)
283 goto no_dirent;
284
285 dirent = ctx->dirent;
286
287 switch (ch) {
288 case 'i':
289 printf("%u", dirent->inode);
290 break;
291 case 'n':
Theodore Ts'ob6f79831998-03-09 13:10:37 +0000292 len = dirent->name_len & 0xFF;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000293 if (len > EXT2_NAME_LEN)
294 len = EXT2_NAME_LEN;
295 if (len > dirent->rec_len)
296 len = dirent->rec_len;
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000297 safe_print(dirent->name, len);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000298 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000299 case 'r':
300 printf("%u", dirent->rec_len);
301 break;
302 case 'l':
Theodore Ts'ob6f79831998-03-09 13:10:37 +0000303 printf("%u", dirent->name_len & 0xFF);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000304 break;
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000305 case 't':
306 printf("%u", dirent->name_len >> 8);
307 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000308 default:
309 no_dirent:
310 printf("%%D%c", ch);
311 break;
312 }
313}
314
315static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
316 struct problem_context *ctx)
317{
318 if (!ctx)
319 goto no_context;
320
321 switch (ch) {
322 case '%':
323 fputc('%', stdout);
324 break;
325 case 'b':
326 printf("%u", ctx->blk);
327 break;
328 case 'B':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000329#ifdef EXT2_NO_64_TYPE
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000330 printf("%d", ctx->blkcount);
Theodore Ts'o246501c1998-03-24 16:22:38 +0000331#else
332 printf("%lld", ctx->blkcount);
333#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000334 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000335 case 'c':
336 printf("%u", ctx->blk2);
337 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000338 case 'd':
339 printf("%lu", ctx->dir);
340 break;
341 case 'g':
342 printf("%d", ctx->group);
343 break;
344 case 'i':
345 printf("%lu", ctx->ino);
346 break;
347 case 'j':
348 printf("%lu", ctx->ino2);
349 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000350 case 'm':
351 printf("%s", error_message(ctx->errcode));
352 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000353 case 'N':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000354#ifdef EXT2_NO_64_TYPE
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000355 printf("%u", ctx->num);
Theodore Ts'o246501c1998-03-24 16:22:38 +0000356#else
357 printf("%llu", ctx->num);
358#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000359 break;
360 case 'p':
361 print_pathname(fs, ctx->ino, 0);
362 break;
363 case 'P':
364 print_pathname(fs, ctx->ino2,
365 ctx->dirent ? ctx->dirent->inode : 0);
366 break;
367 case 'q':
368 print_pathname(fs, ctx->dir, 0);
369 break;
370 case 'Q':
371 print_pathname(fs, ctx->dir, ctx->ino);
372 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000373 case 'S':
374 printf("%d", get_backup_sb(fs));
375 break;
376 case 's':
377 printf("%s", ctx->str);
378 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000379 default:
380 no_context:
381 printf("%%%c", ch);
382 break;
383 }
384}
385
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000386void print_e2fsck_message(e2fsck_t ctx, const char *msg,
387 struct problem_context *pctx, int first)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000388{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000389 ext2_filsys fs = ctx->fs;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000390 const char * cp;
391 int i;
Theodore Ts'o5596def1999-07-19 15:27:37 +0000392
393 e2fsck_clear_progbar(ctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000394 for (cp = msg; *cp; cp++) {
395 if (cp[0] == '@') {
396 cp++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000397 expand_at_expression(ctx, *cp, pctx, &first);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000398 } else if (cp[0] == '%' && cp[1] == 'I') {
399 cp += 2;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000400 expand_inode_expression(*cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000401 } else if (cp[0] == '%' && cp[1] == 'D') {
402 cp += 2;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000403 expand_dirent_expression(*cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000404 } else if ((cp[0] == '%')) {
405 cp++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000406 expand_percent_expression(fs, *cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000407 } else {
408 for (i=0; cp[i]; i++)
409 if ((cp[i] == '@') || cp[i] == '%')
410 break;
411 printf("%.*s", i, cp);
412 cp += i-1;
413 }
414 first = 0;
415 }
416}