blob: 673c4638d64f57d3eb3b27580d55557053a4a310 [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 *
49 * @b block
50 * @B bitmap
51 * @C conflicts with some other fs block
52 * @i inode
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +000053 * @I illegal
Theodore Ts'o21c84b71997-04-29 16:15:03 +000054 * @D deleted
55 * @d directory
56 * @e entry
57 * @E Entry '%Dn' in %p (%i)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000058 * @f filesystem
Theodore Ts'o21c84b71997-04-29 16:15:03 +000059 * @F for @i %i (%Q) is
60 * @g group
61 * @l lost+found
62 * @L is a link
63 * @u unattached
64 * @r root inode
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000065 * @s should be
66 * @S superblock
Theodore Ts'o21c84b71997-04-29 16:15:03 +000067 * @z zero-length
68 */
69
70#include <stdlib.h>
71#include <unistd.h>
72#include <string.h>
73#include <ctype.h>
74#include <termios.h>
75
76#include "e2fsck.h"
77
78#include "problem.h"
79
80#ifdef __GNUC__
81#define _INLINE_ __inline__
82#else
83#define _INLINE_
84#endif
85
86/*
87 * This structure defines the abbreviations used by the text strings
88 * below. The first character in the string is the index letter. An
89 * abbreviation of the form '@<i>' is expanded by looking up the index
90 * letter <i> in the table below.
91 */
92static const char *abbrevs[] = {
93 "bblock",
94 "Bbitmap",
95 "Cconflicts with some other fs @b",
96 "iinode",
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +000097 "Iillegal",
Theodore Ts'o21c84b71997-04-29 16:15:03 +000098 "Ddeleted",
99 "ddirectory",
100 "eentry",
101 "E@e '%Dn' in %p (%i)",
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000102 "ffilesystem",
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000103 "Ffor @i %i (%Q) is",
104 "ggroup",
105 "llost+found",
106 "Lis a link",
107 "uunattached",
108 "rroot @i",
109 "sshould be",
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000110 "Ssuper@b",
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000111 "zzero-length",
112 "@@",
113 0
114 };
115
116/*
117 * Give more user friendly names to the "special" inodes.
118 */
119#define num_special_inodes 7
120static const char *special_inode_name[] =
121{
122 "<The NULL inode>", /* 0 */
123 "<The bad blocks inode>", /* 1 */
124 "/", /* 2 */
125 "<The ACL index inode>", /* 3 */
126 "<The ACL data inode>", /* 4 */
127 "<The boot loader inode>", /* 5 */
128 "<The undelete directory inode>" /* 6 */
129};
130
131/*
132 * This function prints a pathname, using the ext2fs_get_pathname
133 * function
134 */
135static void print_pathname(ext2_filsys fs, ino_t dir, ino_t ino)
136{
137 errcode_t retval;
138 char *path;
139
140 if (!dir && (ino < num_special_inodes)) {
141 fputs(special_inode_name[ino], stdout);
142 return;
143 }
144
145 retval = ext2fs_get_pathname(fs, dir, ino, &path);
146 if (retval)
147 fputs("???", stdout);
148 else {
149 fputs(path, stdout);
150 free(path);
151 }
152}
153
154/*
155 * This function handles the '@' expansion. We allow recursive
156 * expansion; an @ expression can contain further '@' and '%'
157 * expressions.
158 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000159static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
160 struct problem_context *pctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000161 int *first)
162{
163 const char **cpp, *str;
164
165 /* Search for the abbreviation */
166 for (cpp = abbrevs; *cpp; cpp++) {
167 if (ch == *cpp[0])
168 break;
169 }
170 if (*cpp) {
171 str = (*cpp) + 1;
172 if (*first && islower(*str)) {
173 *first = 0;
174 fputc(toupper(*str++), stdout);
175 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000176 print_e2fsck_message(ctx, str, pctx, *first);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000177 } else
178 printf("@%c", ch);
179}
180
181/*
182 * This function expands '%kX' expressions
183 */
184static _INLINE_ void expand_inode_expression(char ch,
185 struct problem_context *ctx)
186{
187 struct ext2_inode *inode;
188 char * time_str;
189 time_t t;
190
191 if (!ctx || !ctx->inode)
192 goto no_inode;
193
194 inode = ctx->inode;
195
196 switch (ch) {
197 case 's':
198 printf("%u", inode->i_size);
199 break;
200 case 'b':
201 printf("%u", inode->i_blocks);
202 break;
203 case 'l':
204 printf("%d", inode->i_links_count);
205 break;
206 case 'm':
207 printf("0%o", inode->i_mode);
208 break;
209 case 'M':
210 t = inode->i_mtime;
211 time_str = ctime(&t);
212 printf("%.24s", time_str);
213 break;
214 case 'F':
215 printf("%u", inode->i_faddr);
216 break;
217 case 'f':
218 printf("%u", inode->i_file_acl);
219 break;
220 case 'd':
221 printf("%u", inode->i_dir_acl);
222 break;
223 default:
224 no_inode:
225 printf("%%I%c", ch);
226 break;
227 }
228}
229
230/*
231 * This function expands '%dX' expressions
232 */
233static _INLINE_ void expand_dirent_expression(char ch,
234 struct problem_context *ctx)
235{
236 struct ext2_dir_entry *dirent;
237 int len;
238
239 if (!ctx || !ctx->dirent)
240 goto no_dirent;
241
242 dirent = ctx->dirent;
243
244 switch (ch) {
245 case 'i':
246 printf("%u", dirent->inode);
247 break;
248 case 'n':
249 len = dirent->name_len;
250 if (len > EXT2_NAME_LEN)
251 len = EXT2_NAME_LEN;
252 if (len > dirent->rec_len)
253 len = dirent->rec_len;
254 printf("%.*s", dirent->name_len, dirent->name);
255 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000256 case 'r':
257 printf("%u", dirent->rec_len);
258 break;
259 case 'l':
260 printf("%u", dirent->name_len);
261 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000262 default:
263 no_dirent:
264 printf("%%D%c", ch);
265 break;
266 }
267}
268
269static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
270 struct problem_context *ctx)
271{
272 if (!ctx)
273 goto no_context;
274
275 switch (ch) {
276 case '%':
277 fputc('%', stdout);
278 break;
279 case 'b':
280 printf("%u", ctx->blk);
281 break;
282 case 'B':
283 printf("%d", ctx->blkcount);
284 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000285 case 'c':
286 printf("%u", ctx->blk2);
287 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000288 case 'd':
289 printf("%lu", ctx->dir);
290 break;
291 case 'g':
292 printf("%d", ctx->group);
293 break;
294 case 'i':
295 printf("%lu", ctx->ino);
296 break;
297 case 'j':
298 printf("%lu", ctx->ino2);
299 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000300 case 'm':
301 printf("%s", error_message(ctx->errcode));
302 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000303 case 'N':
304 printf("%u", ctx->num);
305 break;
306 case 'p':
307 print_pathname(fs, ctx->ino, 0);
308 break;
309 case 'P':
310 print_pathname(fs, ctx->ino2,
311 ctx->dirent ? ctx->dirent->inode : 0);
312 break;
313 case 'q':
314 print_pathname(fs, ctx->dir, 0);
315 break;
316 case 'Q':
317 print_pathname(fs, ctx->dir, ctx->ino);
318 break;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000319 case 'S':
320 printf("%d", get_backup_sb(fs));
321 break;
322 case 's':
323 printf("%s", ctx->str);
324 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000325 default:
326 no_context:
327 printf("%%%c", ch);
328 break;
329 }
330}
331
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000332void print_e2fsck_message(e2fsck_t ctx, const char *msg,
333 struct problem_context *pctx, int first)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000334{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000335 ext2_filsys fs = ctx->fs;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000336 const char * cp;
337 int i;
338
339 for (cp = msg; *cp; cp++) {
340 if (cp[0] == '@') {
341 cp++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000342 expand_at_expression(ctx, *cp, pctx, &first);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000343 } else if (cp[0] == '%' && cp[1] == 'I') {
344 cp += 2;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000345 expand_inode_expression(*cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000346 } else if (cp[0] == '%' && cp[1] == 'D') {
347 cp += 2;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000348 expand_dirent_expression(*cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000349 } else if ((cp[0] == '%')) {
350 cp++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000351 expand_percent_expression(fs, *cp, pctx);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000352 } else {
353 for (i=0; cp[i]; i++)
354 if ((cp[i] == '@') || cp[i] == '%')
355 break;
356 printf("%.*s", i, cp);
357 cp += i-1;
358 }
359 first = 0;
360 }
361}