blob: 7622dcbae9d10d85a3bb66d8a6a5205b690cc676 [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'o3b5386d2000-08-14 14:25:19 +000047 * %X <num> hexadecimal format
Theodore Ts'o21c84b71997-04-29 16:15:03 +000048 *
49 * The following '@' expansions are supported:
50 *
Theodore Ts'of8188ff1997-11-14 05:23:04 +000051 * @A error allocating
Theodore Ts'o21c84b71997-04-29 16:15:03 +000052 * @b block
53 * @B bitmap
Theodore Ts'o19178752000-02-11 15:55:07 +000054 * @c compress
Theodore Ts'o21c84b71997-04-29 16:15:03 +000055 * @C conflicts with some other fs block
56 * @i inode
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +000057 * @I illegal
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
65 * @l lost+found
66 * @L is a link
Theodore Ts'o80bfaa32000-08-18 15:08:37 +000067 * @o orphaned
Theodore Ts'o21c84b71997-04-29 16:15:03 +000068 * @r root inode
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000069 * @s should be
70 * @S superblock
Theodore Ts'o80bfaa32000-08-18 15:08:37 +000071 * @u unattached
Theodore Ts'o21c84b71997-04-29 16:15:03 +000072 * @z zero-length
73 */
74
75#include <stdlib.h>
76#include <unistd.h>
77#include <string.h>
78#include <ctype.h>
79#include <termios.h>
80
81#include "e2fsck.h"
82
83#include "problem.h"
84
85#ifdef __GNUC__
86#define _INLINE_ __inline__
87#else
88#define _INLINE_
89#endif
90
91/*
92 * This structure defines the abbreviations used by the text strings
93 * below. The first character in the string is the index letter. An
94 * abbreviation of the form '@<i>' is expanded by looking up the index
95 * letter <i> in the table below.
96 */
97static const char *abbrevs[] = {
Theodore Ts'o0c4a0722000-02-07 03:11:03 +000098 N_("Aerror allocating"),
99 N_("bblock"),
100 N_("Bbitmap"),
Theodore Ts'o19178752000-02-11 15:55:07 +0000101 N_("ccompress"),
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000102 N_("Cconflicts with some other fs @b"),
103 N_("iinode"),
104 N_("Iillegal"),
105 N_("Ddeleted"),
106 N_("ddirectory"),
107 N_("eentry"),
108 N_("E@e '%Dn' in %p (%i)"),
109 N_("ffilesystem"),
110 N_("Ffor @i %i (%Q) is"),
111 N_("ggroup"),
112 N_("llost+found"),
113 N_("Lis a link"),
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000114 N_("oorphaned"),
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000115 N_("rroot @i"),
116 N_("sshould be"),
117 N_("Ssuper@b"),
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000118 N_("uunattached"),
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000119 N_("zzero-length"),
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000120 "@@",
121 0
122 };
123
124/*
125 * Give more user friendly names to the "special" inodes.
126 */
127#define num_special_inodes 7
128static const char *special_inode_name[] =
129{
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000130 N_("<The NULL inode>"), /* 0 */
131 N_("<The bad blocks inode>"), /* 1 */
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000132 "/", /* 2 */
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000133 N_("<The ACL index inode>"), /* 3 */
134 N_("<The ACL data inode>"), /* 4 */
135 N_("<The boot loader inode>"), /* 5 */
136 N_("<The undelete directory inode>") /* 6 */
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000137};
138
139/*
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000140 * This function does "safe" printing. It will convert non-printable
141 * ASCII characters using '^' and M- notation.
142 */
Theodore Ts'of68aa411999-10-26 14:20:22 +0000143static void safe_print(const char *cp, int len)
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000144{
145 unsigned char ch;
146
147 if (len < 0)
148 len = strlen(cp);
149
150 while (len--) {
151 ch = *cp++;
152 if (ch > 128) {
153 fputs("M-", stdout);
154 ch -= 128;
155 }
Theodore Ts'oec8d2c31999-11-19 18:52:36 +0000156 if ((ch < 32) || (ch == 0x7f)) {
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000157 fputc('^', stdout);
Theodore Ts'oec8d2c31999-11-19 18:52:36 +0000158 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000159 }
160 fputc(ch, stdout);
161 }
162}
163
164
165/*
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000166 * This function prints a pathname, using the ext2fs_get_pathname
167 * function
168 */
169static void print_pathname(ext2_filsys fs, ino_t dir, ino_t ino)
170{
171 errcode_t retval;
172 char *path;
173
174 if (!dir && (ino < num_special_inodes)) {
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000175 fputs(_(special_inode_name[ino]), stdout);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000176 return;
177 }
178
179 retval = ext2fs_get_pathname(fs, dir, ino, &path);
180 if (retval)
181 fputs("???", stdout);
182 else {
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000183 safe_print(path, -1);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000184 ext2fs_free_mem((void **) &path);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000185 }
186}
187
188/*
189 * This function handles the '@' expansion. We allow recursive
190 * expansion; an @ expression can contain further '@' and '%'
191 * expressions.
192 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000193static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
194 struct problem_context *pctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000195 int *first)
196{
197 const char **cpp, *str;
198
199 /* Search for the abbreviation */
200 for (cpp = abbrevs; *cpp; cpp++) {
201 if (ch == *cpp[0])
202 break;
203 }
204 if (*cpp) {
205 str = (*cpp) + 1;
206 if (*first && islower(*str)) {
207 *first = 0;
208 fputc(toupper(*str++), stdout);
209 }
Theodore Ts'o0c4a0722000-02-07 03:11:03 +0000210 print_e2fsck_message(ctx, _(str), pctx, *first);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000211 } else
212 printf("@%c", ch);
213}
214
215/*
216 * This function expands '%kX' expressions
217 */
218static _INLINE_ void expand_inode_expression(char ch,
219 struct problem_context *ctx)
220{
221 struct ext2_inode *inode;
222 char * time_str;
223 time_t t;
224
225 if (!ctx || !ctx->inode)
226 goto no_inode;
227
228 inode = ctx->inode;
229
230 switch (ch) {
231 case 's':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000232 if (LINUX_S_ISDIR(inode->i_mode))
233 printf("%u", inode->i_size);
234 else {
235#ifdef EXT2_NO_64_TYPE
236 if (inode->i_size_high)
237 printf("0x%x%08x", inode->i_size_high,
238 inode->i_size);
239 else
240 printf("%u", inode->i_size);
241#else
242 printf("%llu", (inode->i_size |
243 ((__u64) inode->i_size_high << 32)));
244#endif
245 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000246 break;
247 case 'b':
248 printf("%u", inode->i_blocks);
249 break;
250 case 'l':
251 printf("%d", inode->i_links_count);
252 break;
253 case 'm':
254 printf("0%o", inode->i_mode);
255 break;
256 case 'M':
257 t = inode->i_mtime;
258 time_str = ctime(&t);
259 printf("%.24s", time_str);
260 break;
261 case 'F':
262 printf("%u", inode->i_faddr);
263 break;
264 case 'f':
265 printf("%u", inode->i_file_acl);
266 break;
267 case 'd':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000268 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
269 inode->i_dir_acl : 0));
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000270 break;
271 default:
272 no_inode:
273 printf("%%I%c", ch);
274 break;
275 }
276}
277
278/*
279 * This function expands '%dX' expressions
280 */
281static _INLINE_ void expand_dirent_expression(char ch,
282 struct problem_context *ctx)
283{
284 struct ext2_dir_entry *dirent;
285 int len;
286
287 if (!ctx || !ctx->dirent)
288 goto no_dirent;
289
290 dirent = ctx->dirent;
291
292 switch (ch) {
293 case 'i':
294 printf("%u", dirent->inode);
295 break;
296 case 'n':
Theodore Ts'ob6f79831998-03-09 13:10:37 +0000297 len = dirent->name_len & 0xFF;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000298 if (len > EXT2_NAME_LEN)
299 len = EXT2_NAME_LEN;
300 if (len > dirent->rec_len)
301 len = dirent->rec_len;
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000302 safe_print(dirent->name, len);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000303 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000304 case 'r':
305 printf("%u", dirent->rec_len);
306 break;
307 case 'l':
Theodore Ts'ob6f79831998-03-09 13:10:37 +0000308 printf("%u", dirent->name_len & 0xFF);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000309 break;
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000310 case 't':
311 printf("%u", dirent->name_len >> 8);
312 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000313 default:
314 no_dirent:
315 printf("%%D%c", ch);
316 break;
317 }
318}
319
320static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
321 struct problem_context *ctx)
322{
323 if (!ctx)
324 goto no_context;
325
326 switch (ch) {
327 case '%':
328 fputc('%', stdout);
329 break;
330 case 'b':
331 printf("%u", ctx->blk);
332 break;
333 case 'B':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000334#ifdef EXT2_NO_64_TYPE
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000335 printf("%d", ctx->blkcount);
Theodore Ts'o246501c1998-03-24 16:22:38 +0000336#else
337 printf("%lld", ctx->blkcount);
338#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000339 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000340 case 'c':
341 printf("%u", ctx->blk2);
342 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000343 case 'd':
344 printf("%lu", ctx->dir);
345 break;
346 case 'g':
347 printf("%d", ctx->group);
348 break;
349 case 'i':
350 printf("%lu", ctx->ino);
351 break;
352 case 'j':
353 printf("%lu", ctx->ino2);
354 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000355 case 'm':
356 printf("%s", error_message(ctx->errcode));
357 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000358 case 'N':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000359#ifdef EXT2_NO_64_TYPE
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000360 printf("%u", ctx->num);
Theodore Ts'o246501c1998-03-24 16:22:38 +0000361#else
362 printf("%llu", ctx->num);
363#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000364 break;
365 case 'p':
366 print_pathname(fs, ctx->ino, 0);
367 break;
368 case 'P':
369 print_pathname(fs, ctx->ino2,
370 ctx->dirent ? ctx->dirent->inode : 0);
371 break;
372 case 'q':
373 print_pathname(fs, ctx->dir, 0);
374 break;
375 case 'Q':
376 print_pathname(fs, ctx->dir, ctx->ino);
377 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000378 case 'S':
379 printf("%d", get_backup_sb(fs));
380 break;
381 case 's':
382 printf("%s", ctx->str);
383 break;
Theodore Ts'o3b5386d2000-08-14 14:25:19 +0000384 case 'X':
385#ifdef EXT2_NO_64_TYPE
386 printf("0x%x", ctx->num);
387#else
388 printf("0x%llx", ctx->num);
389#endif
390 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000391 default:
392 no_context:
393 printf("%%%c", ch);
394 break;
395 }
396}
397
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000398void print_e2fsck_message(e2fsck_t ctx, const char *msg,
399 struct problem_context *pctx, int first)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000400{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000401 ext2_filsys fs = ctx->fs;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000402 const char * cp;
403 int i;
Theodore Ts'o5596def1999-07-19 15:27:37 +0000404
405 e2fsck_clear_progbar(ctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000406 for (cp = msg; *cp; cp++) {
407 if (cp[0] == '@') {
408 cp++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000409 expand_at_expression(ctx, *cp, pctx, &first);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000410 } else if (cp[0] == '%' && cp[1] == 'I') {
411 cp += 2;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000412 expand_inode_expression(*cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000413 } else if (cp[0] == '%' && cp[1] == 'D') {
414 cp += 2;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000415 expand_dirent_expression(*cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000416 } else if ((cp[0] == '%')) {
417 cp++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000418 expand_percent_expression(fs, *cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000419 } else {
420 for (i=0; cp[i]; i++)
421 if ((cp[i] == '@') || cp[i] == '%')
422 break;
423 printf("%.*s", i, cp);
424 cp += i-1;
425 }
426 first = 0;
427 }
428}