blob: 1e440c5cf47f525e0ee172275d9e199baa4cfc79 [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'o21c84b71997-04-29 16:15:03 +000023 * %D <dir> inode number
24 * %g <group> integer
25 * %i <ino> inode number
26 * %Is <inode> -> i_size
27 * %Ib <inode> -> i_blocks
28 * %Il <inode> -> i_links_count
29 * %Im <inode> -> i_mode
30 * %IM <inode> -> i_mtime
31 * %IF <inode> -> i_faddr
32 * %If <inode> -> i_file_acl
33 * %Id <inode> -> i_dir_acl
34 * %j <ino2> inode number
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000035 * %m <com_err error message>
Theodore Ts'o21c84b71997-04-29 16:15:03 +000036 * %N <num>
37 * %p ext2fs_get_pathname of directory <ino>
38 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
39 * the containing directory. (If dirent is NULL
40 * then return the pathname of directory <ino2>)
41 * %q ext2fs_get_pathname of directory <dir>
42 * %Q ext2fs_get_pathname of directory <ino> with <dir> as
43 * the containing directory.
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000044 * %s <str> miscellaneous string
45 * %S backup superblock
Theodore Ts'o21c84b71997-04-29 16:15:03 +000046 *
47 * The following '@' expansions are supported:
48 *
Theodore Ts'of8188ff1997-11-14 05:23:04 +000049 * @A error allocating
Theodore Ts'o21c84b71997-04-29 16:15:03 +000050 * @b block
51 * @B bitmap
52 * @C conflicts with some other fs block
53 * @i inode
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +000054 * @I illegal
Theodore Ts'o21c84b71997-04-29 16:15:03 +000055 * @D deleted
56 * @d directory
57 * @e entry
58 * @E Entry '%Dn' in %p (%i)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000059 * @f filesystem
Theodore Ts'o21c84b71997-04-29 16:15:03 +000060 * @F for @i %i (%Q) is
61 * @g group
62 * @l lost+found
63 * @L is a link
64 * @u unattached
65 * @r root inode
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000066 * @s should be
67 * @S superblock
Theodore Ts'o21c84b71997-04-29 16:15:03 +000068 * @z zero-length
69 */
70
71#include <stdlib.h>
72#include <unistd.h>
73#include <string.h>
74#include <ctype.h>
75#include <termios.h>
76
77#include "e2fsck.h"
78
79#include "problem.h"
80
81#ifdef __GNUC__
82#define _INLINE_ __inline__
83#else
84#define _INLINE_
85#endif
86
87/*
88 * This structure defines the abbreviations used by the text strings
89 * below. The first character in the string is the index letter. An
90 * abbreviation of the form '@<i>' is expanded by looking up the index
91 * letter <i> in the table below.
92 */
93static const char *abbrevs[] = {
Theodore Ts'of8188ff1997-11-14 05:23:04 +000094 "Aerror allocating",
Theodore Ts'o21c84b71997-04-29 16:15:03 +000095 "bblock",
96 "Bbitmap",
97 "Cconflicts with some other fs @b",
98 "iinode",
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +000099 "Iillegal",
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000100 "Ddeleted",
101 "ddirectory",
102 "eentry",
103 "E@e '%Dn' in %p (%i)",
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000104 "ffilesystem",
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000105 "Ffor @i %i (%Q) is",
106 "ggroup",
107 "llost+found",
108 "Lis a link",
109 "uunattached",
110 "rroot @i",
111 "sshould be",
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000112 "Ssuper@b",
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000113 "zzero-length",
114 "@@",
115 0
116 };
117
118/*
119 * Give more user friendly names to the "special" inodes.
120 */
121#define num_special_inodes 7
122static const char *special_inode_name[] =
123{
124 "<The NULL inode>", /* 0 */
125 "<The bad blocks inode>", /* 1 */
126 "/", /* 2 */
127 "<The ACL index inode>", /* 3 */
128 "<The ACL data inode>", /* 4 */
129 "<The boot loader inode>", /* 5 */
130 "<The undelete directory inode>" /* 6 */
131};
132
133/*
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000134 * This function does "safe" printing. It will convert non-printable
135 * ASCII characters using '^' and M- notation.
136 */
137static void safe_print(const unsigned char *cp, int len)
138{
139 unsigned char ch;
140
141 if (len < 0)
142 len = strlen(cp);
143
144 while (len--) {
145 ch = *cp++;
146 if (ch > 128) {
147 fputs("M-", stdout);
148 ch -= 128;
149 }
150 if (ch < 32) {
151 fputc('^', stdout);
152 ch += 32;
153 }
154 fputc(ch, stdout);
155 }
156}
157
158
159/*
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000160 * This function prints a pathname, using the ext2fs_get_pathname
161 * function
162 */
163static void print_pathname(ext2_filsys fs, ino_t dir, ino_t ino)
164{
165 errcode_t retval;
166 char *path;
167
168 if (!dir && (ino < num_special_inodes)) {
169 fputs(special_inode_name[ino], stdout);
170 return;
171 }
172
173 retval = ext2fs_get_pathname(fs, dir, ino, &path);
174 if (retval)
175 fputs("???", stdout);
176 else {
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000177 safe_print(path, -1);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000178 ext2fs_free_mem((void **) &path);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000179 }
180}
181
182/*
183 * This function handles the '@' expansion. We allow recursive
184 * expansion; an @ expression can contain further '@' and '%'
185 * expressions.
186 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000187static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
188 struct problem_context *pctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000189 int *first)
190{
191 const char **cpp, *str;
192
193 /* Search for the abbreviation */
194 for (cpp = abbrevs; *cpp; cpp++) {
195 if (ch == *cpp[0])
196 break;
197 }
198 if (*cpp) {
199 str = (*cpp) + 1;
200 if (*first && islower(*str)) {
201 *first = 0;
202 fputc(toupper(*str++), stdout);
203 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000204 print_e2fsck_message(ctx, str, pctx, *first);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000205 } else
206 printf("@%c", ch);
207}
208
209/*
210 * This function expands '%kX' expressions
211 */
212static _INLINE_ void expand_inode_expression(char ch,
213 struct problem_context *ctx)
214{
215 struct ext2_inode *inode;
216 char * time_str;
217 time_t t;
218
219 if (!ctx || !ctx->inode)
220 goto no_inode;
221
222 inode = ctx->inode;
223
224 switch (ch) {
225 case 's':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000226 if (LINUX_S_ISDIR(inode->i_mode))
227 printf("%u", inode->i_size);
228 else {
229#ifdef EXT2_NO_64_TYPE
230 if (inode->i_size_high)
231 printf("0x%x%08x", inode->i_size_high,
232 inode->i_size);
233 else
234 printf("%u", inode->i_size);
235#else
236 printf("%llu", (inode->i_size |
237 ((__u64) inode->i_size_high << 32)));
238#endif
239 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000240 break;
241 case 'b':
242 printf("%u", inode->i_blocks);
243 break;
244 case 'l':
245 printf("%d", inode->i_links_count);
246 break;
247 case 'm':
248 printf("0%o", inode->i_mode);
249 break;
250 case 'M':
251 t = inode->i_mtime;
252 time_str = ctime(&t);
253 printf("%.24s", time_str);
254 break;
255 case 'F':
256 printf("%u", inode->i_faddr);
257 break;
258 case 'f':
259 printf("%u", inode->i_file_acl);
260 break;
261 case 'd':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000262 printf("%u", (LINUX_S_ISDIR(inode->i_mode) ?
263 inode->i_dir_acl : 0));
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000264 break;
265 default:
266 no_inode:
267 printf("%%I%c", ch);
268 break;
269 }
270}
271
272/*
273 * This function expands '%dX' expressions
274 */
275static _INLINE_ void expand_dirent_expression(char ch,
276 struct problem_context *ctx)
277{
278 struct ext2_dir_entry *dirent;
279 int len;
280
281 if (!ctx || !ctx->dirent)
282 goto no_dirent;
283
284 dirent = ctx->dirent;
285
286 switch (ch) {
287 case 'i':
288 printf("%u", dirent->inode);
289 break;
290 case 'n':
Theodore Ts'ob6f79831998-03-09 13:10:37 +0000291 len = dirent->name_len & 0xFF;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000292 if (len > EXT2_NAME_LEN)
293 len = EXT2_NAME_LEN;
294 if (len > dirent->rec_len)
295 len = dirent->rec_len;
Theodore Ts'o9e51eca1999-01-09 16:32:31 +0000296 safe_print(dirent->name, len);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000297 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000298 case 'r':
299 printf("%u", dirent->rec_len);
300 break;
301 case 'l':
Theodore Ts'ob6f79831998-03-09 13:10:37 +0000302 printf("%u", dirent->name_len & 0xFF);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000303 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000304 default:
305 no_dirent:
306 printf("%%D%c", ch);
307 break;
308 }
309}
310
311static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
312 struct problem_context *ctx)
313{
314 if (!ctx)
315 goto no_context;
316
317 switch (ch) {
318 case '%':
319 fputc('%', stdout);
320 break;
321 case 'b':
322 printf("%u", ctx->blk);
323 break;
324 case 'B':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000325#ifdef EXT2_NO_64_TYPE
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000326 printf("%d", ctx->blkcount);
Theodore Ts'o246501c1998-03-24 16:22:38 +0000327#else
328 printf("%lld", ctx->blkcount);
329#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000330 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000331 case 'c':
332 printf("%u", ctx->blk2);
333 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000334 case 'd':
335 printf("%lu", ctx->dir);
336 break;
337 case 'g':
338 printf("%d", ctx->group);
339 break;
340 case 'i':
341 printf("%lu", ctx->ino);
342 break;
343 case 'j':
344 printf("%lu", ctx->ino2);
345 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000346 case 'm':
347 printf("%s", error_message(ctx->errcode));
348 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000349 case 'N':
Theodore Ts'o246501c1998-03-24 16:22:38 +0000350#ifdef EXT2_NO_64_TYPE
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000351 printf("%u", ctx->num);
Theodore Ts'o246501c1998-03-24 16:22:38 +0000352#else
353 printf("%llu", ctx->num);
354#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000355 break;
356 case 'p':
357 print_pathname(fs, ctx->ino, 0);
358 break;
359 case 'P':
360 print_pathname(fs, ctx->ino2,
361 ctx->dirent ? ctx->dirent->inode : 0);
362 break;
363 case 'q':
364 print_pathname(fs, ctx->dir, 0);
365 break;
366 case 'Q':
367 print_pathname(fs, ctx->dir, ctx->ino);
368 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000369 case 'S':
370 printf("%d", get_backup_sb(fs));
371 break;
372 case 's':
373 printf("%s", ctx->str);
374 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000375 default:
376 no_context:
377 printf("%%%c", ch);
378 break;
379 }
380}
381
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000382void print_e2fsck_message(e2fsck_t ctx, const char *msg,
383 struct problem_context *pctx, int first)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000384{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000385 ext2_filsys fs = ctx->fs;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000386 const char * cp;
387 int i;
388
389 for (cp = msg; *cp; cp++) {
390 if (cp[0] == '@') {
391 cp++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000392 expand_at_expression(ctx, *cp, pctx, &first);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000393 } else if (cp[0] == '%' && cp[1] == 'I') {
394 cp += 2;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000395 expand_inode_expression(*cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000396 } else if (cp[0] == '%' && cp[1] == 'D') {
397 cp += 2;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000398 expand_dirent_expression(*cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000399 } else if ((cp[0] == '%')) {
400 cp++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000401 expand_percent_expression(fs, *cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000402 } else {
403 for (i=0; cp[i]; i++)
404 if ((cp[i] == '@') || cp[i] == '%')
405 break;
406 printf("%.*s", i, cp);
407 cp += i-1;
408 }
409 first = 0;
410 }
411}