blob: c5f2593835b93f5257c6d727766c114d0c905d0c [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
18 * %di <dirent>->ino inode number
19 * %dn <dirent>->name string
20 * %D <dir> inode number
21 * %g <group> integer
22 * %i <ino> inode number
23 * %Is <inode> -> i_size
24 * %Ib <inode> -> i_blocks
25 * %Il <inode> -> i_links_count
26 * %Im <inode> -> i_mode
27 * %IM <inode> -> i_mtime
28 * %IF <inode> -> i_faddr
29 * %If <inode> -> i_file_acl
30 * %Id <inode> -> i_dir_acl
31 * %j <ino2> inode number
32 * %N <num>
33 * %p ext2fs_get_pathname of directory <ino>
34 * %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
35 * the containing directory. (If dirent is NULL
36 * then return the pathname of directory <ino2>)
37 * %q ext2fs_get_pathname of directory <dir>
38 * %Q ext2fs_get_pathname of directory <ino> with <dir> as
39 * the containing directory.
40 *
41 * The following '@' expansions are supported:
42 *
43 * @b block
44 * @B bitmap
45 * @C conflicts with some other fs block
46 * @i inode
47 * @D deleted
48 * @d directory
49 * @e entry
50 * @E Entry '%Dn' in %p (%i)
51 * @F for @i %i (%Q) is
52 * @g group
53 * @l lost+found
54 * @L is a link
55 * @u unattached
56 * @r root inode
57 * @z zero-length
58 */
59
60#include <stdlib.h>
61#include <unistd.h>
62#include <string.h>
63#include <ctype.h>
64#include <termios.h>
65
66#include "e2fsck.h"
67
68#include "problem.h"
69
70#ifdef __GNUC__
71#define _INLINE_ __inline__
72#else
73#define _INLINE_
74#endif
75
76/*
77 * This structure defines the abbreviations used by the text strings
78 * below. The first character in the string is the index letter. An
79 * abbreviation of the form '@<i>' is expanded by looking up the index
80 * letter <i> in the table below.
81 */
82static const char *abbrevs[] = {
83 "bblock",
84 "Bbitmap",
85 "Cconflicts with some other fs @b",
86 "iinode",
87 "Ddeleted",
88 "ddirectory",
89 "eentry",
90 "E@e '%Dn' in %p (%i)",
91 "Ffor @i %i (%Q) is",
92 "ggroup",
93 "llost+found",
94 "Lis a link",
95 "uunattached",
96 "rroot @i",
97 "sshould be",
98 "zzero-length",
99 "@@",
100 0
101 };
102
103/*
104 * Give more user friendly names to the "special" inodes.
105 */
106#define num_special_inodes 7
107static const char *special_inode_name[] =
108{
109 "<The NULL inode>", /* 0 */
110 "<The bad blocks inode>", /* 1 */
111 "/", /* 2 */
112 "<The ACL index inode>", /* 3 */
113 "<The ACL data inode>", /* 4 */
114 "<The boot loader inode>", /* 5 */
115 "<The undelete directory inode>" /* 6 */
116};
117
118/*
119 * This function prints a pathname, using the ext2fs_get_pathname
120 * function
121 */
122static void print_pathname(ext2_filsys fs, ino_t dir, ino_t ino)
123{
124 errcode_t retval;
125 char *path;
126
127 if (!dir && (ino < num_special_inodes)) {
128 fputs(special_inode_name[ino], stdout);
129 return;
130 }
131
132 retval = ext2fs_get_pathname(fs, dir, ino, &path);
133 if (retval)
134 fputs("???", stdout);
135 else {
136 fputs(path, stdout);
137 free(path);
138 }
139}
140
141/*
142 * This function handles the '@' expansion. We allow recursive
143 * expansion; an @ expression can contain further '@' and '%'
144 * expressions.
145 */
146static _INLINE_ void expand_at_expression(ext2_filsys fs, char ch,
147 struct problem_context *ctx,
148 int *first)
149{
150 const char **cpp, *str;
151
152 /* Search for the abbreviation */
153 for (cpp = abbrevs; *cpp; cpp++) {
154 if (ch == *cpp[0])
155 break;
156 }
157 if (*cpp) {
158 str = (*cpp) + 1;
159 if (*first && islower(*str)) {
160 *first = 0;
161 fputc(toupper(*str++), stdout);
162 }
163 print_e2fsck_message(fs, str, ctx, *first);
164 } else
165 printf("@%c", ch);
166}
167
168/*
169 * This function expands '%kX' expressions
170 */
171static _INLINE_ void expand_inode_expression(char ch,
172 struct problem_context *ctx)
173{
174 struct ext2_inode *inode;
175 char * time_str;
176 time_t t;
177
178 if (!ctx || !ctx->inode)
179 goto no_inode;
180
181 inode = ctx->inode;
182
183 switch (ch) {
184 case 's':
185 printf("%u", inode->i_size);
186 break;
187 case 'b':
188 printf("%u", inode->i_blocks);
189 break;
190 case 'l':
191 printf("%d", inode->i_links_count);
192 break;
193 case 'm':
194 printf("0%o", inode->i_mode);
195 break;
196 case 'M':
197 t = inode->i_mtime;
198 time_str = ctime(&t);
199 printf("%.24s", time_str);
200 break;
201 case 'F':
202 printf("%u", inode->i_faddr);
203 break;
204 case 'f':
205 printf("%u", inode->i_file_acl);
206 break;
207 case 'd':
208 printf("%u", inode->i_dir_acl);
209 break;
210 default:
211 no_inode:
212 printf("%%I%c", ch);
213 break;
214 }
215}
216
217/*
218 * This function expands '%dX' expressions
219 */
220static _INLINE_ void expand_dirent_expression(char ch,
221 struct problem_context *ctx)
222{
223 struct ext2_dir_entry *dirent;
224 int len;
225
226 if (!ctx || !ctx->dirent)
227 goto no_dirent;
228
229 dirent = ctx->dirent;
230
231 switch (ch) {
232 case 'i':
233 printf("%u", dirent->inode);
234 break;
235 case 'n':
236 len = dirent->name_len;
237 if (len > EXT2_NAME_LEN)
238 len = EXT2_NAME_LEN;
239 if (len > dirent->rec_len)
240 len = dirent->rec_len;
241 printf("%.*s", dirent->name_len, dirent->name);
242 break;
243 default:
244 no_dirent:
245 printf("%%D%c", ch);
246 break;
247 }
248}
249
250static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
251 struct problem_context *ctx)
252{
253 if (!ctx)
254 goto no_context;
255
256 switch (ch) {
257 case '%':
258 fputc('%', stdout);
259 break;
260 case 'b':
261 printf("%u", ctx->blk);
262 break;
263 case 'B':
264 printf("%d", ctx->blkcount);
265 break;
266 case 'd':
267 printf("%lu", ctx->dir);
268 break;
269 case 'g':
270 printf("%d", ctx->group);
271 break;
272 case 'i':
273 printf("%lu", ctx->ino);
274 break;
275 case 'j':
276 printf("%lu", ctx->ino2);
277 break;
278 case 'N':
279 printf("%u", ctx->num);
280 break;
281 case 'p':
282 print_pathname(fs, ctx->ino, 0);
283 break;
284 case 'P':
285 print_pathname(fs, ctx->ino2,
286 ctx->dirent ? ctx->dirent->inode : 0);
287 break;
288 case 'q':
289 print_pathname(fs, ctx->dir, 0);
290 break;
291 case 'Q':
292 print_pathname(fs, ctx->dir, ctx->ino);
293 break;
294 default:
295 no_context:
296 printf("%%%c", ch);
297 break;
298 }
299}
300
301void print_e2fsck_message(ext2_filsys fs, const char *msg,
302 struct problem_context *ctx, int first)
303{
304 const char * cp;
305 int i;
306
307 for (cp = msg; *cp; cp++) {
308 if (cp[0] == '@') {
309 cp++;
310 expand_at_expression(fs, *cp, ctx, &first);
311 } else if (cp[0] == '%' && cp[1] == 'I') {
312 cp += 2;
313 expand_inode_expression(*cp, ctx);
314 } else if (cp[0] == '%' && cp[1] == 'D') {
315 cp += 2;
316 expand_dirent_expression(*cp, ctx);
317 } else if ((cp[0] == '%')) {
318 cp++;
319 expand_percent_expression(fs, *cp, ctx);
320 } else {
321 for (i=0; cp[i]; i++)
322 if ((cp[i] == '@') || cp[i] == '%')
323 break;
324 printf("%.*s", i, cp);
325 cp += i-1;
326 }
327 first = 0;
328 }
329}