mirror of
https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git
synced 2025-01-01 14:13:26 +08:00
1b6bf1759a
pass*.c, super.c: Massive changes to avoid using printf and com_err routines. All diagnostic messages are now routed through the fix_problem interface. pass2.c (check_dir_block): Check for duplicate '.' and '..' entries. problem.c, problem.h: Add new problem codes PR_2_DUP_DOT and PR_2_DUP_DOT_DOT. problem.c: Added new problem codes for some of the superblock corruption checks, and for the pass header messages. ("Pass 1: xxxxx") util.c (print_resource_track): Now takes a description argument. super.c, unix.c, e2fsck.c: New files to separate out the operating-specific operations out from e2fsck.c. e2fsck.c now contains the global e2fsck context management routines, and super.c contains the "pass 0" initial validation of the superblock and global block group descriptors. pass1.c, pass2.c, pass3.c, pass4.c, pass5.c, util.c: Eliminate (nearly) all global variables and moved them to the e2fsck context structure. problem.c, problem.h: Added new problem codes PR_0_SB_CORRUPT, PR_0_FS_SIZE_WRONG, PR_0_NO_FRAGMENTS, PR_0_BLOCKS_PER_GROUP, PR_0_FIRST_DATA_BLOCK expect.1, expect.2: Updated tests to align with e2fsck problem.c changes.
362 lines
7.2 KiB
C
362 lines
7.2 KiB
C
/*
|
|
* message.c --- print e2fsck messages (with compression)
|
|
*
|
|
* Copyright 1996, 1997 by Theodore Ts'o
|
|
*
|
|
* %Begin-Header%
|
|
* This file may be redistributed under the terms of the GNU Public
|
|
* License.
|
|
* %End-Header%
|
|
*
|
|
* print_e2fsck_message() prints a message to the user, using
|
|
* compression techniques and expansions of abbreviations.
|
|
*
|
|
* The following % expansions are supported:
|
|
*
|
|
* %b <blk> block number
|
|
* %B <blkcount> integer
|
|
* %c <blk2> block number
|
|
* %di <dirent>->ino inode number
|
|
* %dn <dirent>->name string
|
|
* %dr <dirent>->rec_len
|
|
* %dl <dirent>->name_len
|
|
* %D <dir> inode number
|
|
* %g <group> integer
|
|
* %i <ino> inode number
|
|
* %Is <inode> -> i_size
|
|
* %Ib <inode> -> i_blocks
|
|
* %Il <inode> -> i_links_count
|
|
* %Im <inode> -> i_mode
|
|
* %IM <inode> -> i_mtime
|
|
* %IF <inode> -> i_faddr
|
|
* %If <inode> -> i_file_acl
|
|
* %Id <inode> -> i_dir_acl
|
|
* %j <ino2> inode number
|
|
* %m <com_err error message>
|
|
* %N <num>
|
|
* %p ext2fs_get_pathname of directory <ino>
|
|
* %P ext2fs_get_pathname of <dirent>->ino with <ino2> as
|
|
* the containing directory. (If dirent is NULL
|
|
* then return the pathname of directory <ino2>)
|
|
* %q ext2fs_get_pathname of directory <dir>
|
|
* %Q ext2fs_get_pathname of directory <ino> with <dir> as
|
|
* the containing directory.
|
|
* %s <str> miscellaneous string
|
|
* %S backup superblock
|
|
*
|
|
* The following '@' expansions are supported:
|
|
*
|
|
* @b block
|
|
* @B bitmap
|
|
* @C conflicts with some other fs block
|
|
* @i inode
|
|
* @I illegal
|
|
* @D deleted
|
|
* @d directory
|
|
* @e entry
|
|
* @E Entry '%Dn' in %p (%i)
|
|
* @f filesystem
|
|
* @F for @i %i (%Q) is
|
|
* @g group
|
|
* @l lost+found
|
|
* @L is a link
|
|
* @u unattached
|
|
* @r root inode
|
|
* @s should be
|
|
* @S superblock
|
|
* @z zero-length
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <termios.h>
|
|
|
|
#include "e2fsck.h"
|
|
|
|
#include "problem.h"
|
|
|
|
#ifdef __GNUC__
|
|
#define _INLINE_ __inline__
|
|
#else
|
|
#define _INLINE_
|
|
#endif
|
|
|
|
/*
|
|
* This structure defines the abbreviations used by the text strings
|
|
* below. The first character in the string is the index letter. An
|
|
* abbreviation of the form '@<i>' is expanded by looking up the index
|
|
* letter <i> in the table below.
|
|
*/
|
|
static const char *abbrevs[] = {
|
|
"bblock",
|
|
"Bbitmap",
|
|
"Cconflicts with some other fs @b",
|
|
"iinode",
|
|
"Iillegal",
|
|
"Ddeleted",
|
|
"ddirectory",
|
|
"eentry",
|
|
"E@e '%Dn' in %p (%i)",
|
|
"ffilesystem",
|
|
"Ffor @i %i (%Q) is",
|
|
"ggroup",
|
|
"llost+found",
|
|
"Lis a link",
|
|
"uunattached",
|
|
"rroot @i",
|
|
"sshould be",
|
|
"Ssuper@b",
|
|
"zzero-length",
|
|
"@@",
|
|
0
|
|
};
|
|
|
|
/*
|
|
* Give more user friendly names to the "special" inodes.
|
|
*/
|
|
#define num_special_inodes 7
|
|
static const char *special_inode_name[] =
|
|
{
|
|
"<The NULL inode>", /* 0 */
|
|
"<The bad blocks inode>", /* 1 */
|
|
"/", /* 2 */
|
|
"<The ACL index inode>", /* 3 */
|
|
"<The ACL data inode>", /* 4 */
|
|
"<The boot loader inode>", /* 5 */
|
|
"<The undelete directory inode>" /* 6 */
|
|
};
|
|
|
|
/*
|
|
* This function prints a pathname, using the ext2fs_get_pathname
|
|
* function
|
|
*/
|
|
static void print_pathname(ext2_filsys fs, ino_t dir, ino_t ino)
|
|
{
|
|
errcode_t retval;
|
|
char *path;
|
|
|
|
if (!dir && (ino < num_special_inodes)) {
|
|
fputs(special_inode_name[ino], stdout);
|
|
return;
|
|
}
|
|
|
|
retval = ext2fs_get_pathname(fs, dir, ino, &path);
|
|
if (retval)
|
|
fputs("???", stdout);
|
|
else {
|
|
fputs(path, stdout);
|
|
free(path);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function handles the '@' expansion. We allow recursive
|
|
* expansion; an @ expression can contain further '@' and '%'
|
|
* expressions.
|
|
*/
|
|
static _INLINE_ void expand_at_expression(e2fsck_t ctx, char ch,
|
|
struct problem_context *pctx,
|
|
int *first)
|
|
{
|
|
const char **cpp, *str;
|
|
|
|
/* Search for the abbreviation */
|
|
for (cpp = abbrevs; *cpp; cpp++) {
|
|
if (ch == *cpp[0])
|
|
break;
|
|
}
|
|
if (*cpp) {
|
|
str = (*cpp) + 1;
|
|
if (*first && islower(*str)) {
|
|
*first = 0;
|
|
fputc(toupper(*str++), stdout);
|
|
}
|
|
print_e2fsck_message(ctx, str, pctx, *first);
|
|
} else
|
|
printf("@%c", ch);
|
|
}
|
|
|
|
/*
|
|
* This function expands '%kX' expressions
|
|
*/
|
|
static _INLINE_ void expand_inode_expression(char ch,
|
|
struct problem_context *ctx)
|
|
{
|
|
struct ext2_inode *inode;
|
|
char * time_str;
|
|
time_t t;
|
|
|
|
if (!ctx || !ctx->inode)
|
|
goto no_inode;
|
|
|
|
inode = ctx->inode;
|
|
|
|
switch (ch) {
|
|
case 's':
|
|
printf("%u", inode->i_size);
|
|
break;
|
|
case 'b':
|
|
printf("%u", inode->i_blocks);
|
|
break;
|
|
case 'l':
|
|
printf("%d", inode->i_links_count);
|
|
break;
|
|
case 'm':
|
|
printf("0%o", inode->i_mode);
|
|
break;
|
|
case 'M':
|
|
t = inode->i_mtime;
|
|
time_str = ctime(&t);
|
|
printf("%.24s", time_str);
|
|
break;
|
|
case 'F':
|
|
printf("%u", inode->i_faddr);
|
|
break;
|
|
case 'f':
|
|
printf("%u", inode->i_file_acl);
|
|
break;
|
|
case 'd':
|
|
printf("%u", inode->i_dir_acl);
|
|
break;
|
|
default:
|
|
no_inode:
|
|
printf("%%I%c", ch);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This function expands '%dX' expressions
|
|
*/
|
|
static _INLINE_ void expand_dirent_expression(char ch,
|
|
struct problem_context *ctx)
|
|
{
|
|
struct ext2_dir_entry *dirent;
|
|
int len;
|
|
|
|
if (!ctx || !ctx->dirent)
|
|
goto no_dirent;
|
|
|
|
dirent = ctx->dirent;
|
|
|
|
switch (ch) {
|
|
case 'i':
|
|
printf("%u", dirent->inode);
|
|
break;
|
|
case 'n':
|
|
len = dirent->name_len;
|
|
if (len > EXT2_NAME_LEN)
|
|
len = EXT2_NAME_LEN;
|
|
if (len > dirent->rec_len)
|
|
len = dirent->rec_len;
|
|
printf("%.*s", dirent->name_len, dirent->name);
|
|
break;
|
|
case 'r':
|
|
printf("%u", dirent->rec_len);
|
|
break;
|
|
case 'l':
|
|
printf("%u", dirent->name_len);
|
|
break;
|
|
default:
|
|
no_dirent:
|
|
printf("%%D%c", ch);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static _INLINE_ void expand_percent_expression(ext2_filsys fs, char ch,
|
|
struct problem_context *ctx)
|
|
{
|
|
if (!ctx)
|
|
goto no_context;
|
|
|
|
switch (ch) {
|
|
case '%':
|
|
fputc('%', stdout);
|
|
break;
|
|
case 'b':
|
|
printf("%u", ctx->blk);
|
|
break;
|
|
case 'B':
|
|
printf("%d", ctx->blkcount);
|
|
break;
|
|
case 'c':
|
|
printf("%u", ctx->blk2);
|
|
break;
|
|
case 'd':
|
|
printf("%lu", ctx->dir);
|
|
break;
|
|
case 'g':
|
|
printf("%d", ctx->group);
|
|
break;
|
|
case 'i':
|
|
printf("%lu", ctx->ino);
|
|
break;
|
|
case 'j':
|
|
printf("%lu", ctx->ino2);
|
|
break;
|
|
case 'm':
|
|
printf("%s", error_message(ctx->errcode));
|
|
break;
|
|
case 'N':
|
|
printf("%u", ctx->num);
|
|
break;
|
|
case 'p':
|
|
print_pathname(fs, ctx->ino, 0);
|
|
break;
|
|
case 'P':
|
|
print_pathname(fs, ctx->ino2,
|
|
ctx->dirent ? ctx->dirent->inode : 0);
|
|
break;
|
|
case 'q':
|
|
print_pathname(fs, ctx->dir, 0);
|
|
break;
|
|
case 'Q':
|
|
print_pathname(fs, ctx->dir, ctx->ino);
|
|
break;
|
|
case 'S':
|
|
printf("%d", get_backup_sb(fs));
|
|
break;
|
|
case 's':
|
|
printf("%s", ctx->str);
|
|
break;
|
|
default:
|
|
no_context:
|
|
printf("%%%c", ch);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void print_e2fsck_message(e2fsck_t ctx, const char *msg,
|
|
struct problem_context *pctx, int first)
|
|
{
|
|
ext2_filsys fs = ctx->fs;
|
|
const char * cp;
|
|
int i;
|
|
|
|
for (cp = msg; *cp; cp++) {
|
|
if (cp[0] == '@') {
|
|
cp++;
|
|
expand_at_expression(ctx, *cp, pctx, &first);
|
|
} else if (cp[0] == '%' && cp[1] == 'I') {
|
|
cp += 2;
|
|
expand_inode_expression(*cp, pctx);
|
|
} else if (cp[0] == '%' && cp[1] == 'D') {
|
|
cp += 2;
|
|
expand_dirent_expression(*cp, pctx);
|
|
} else if ((cp[0] == '%')) {
|
|
cp++;
|
|
expand_percent_expression(fs, *cp, pctx);
|
|
} else {
|
|
for (i=0; cp[i]; i++)
|
|
if ((cp[i] == '@') || cp[i] == '%')
|
|
break;
|
|
printf("%.*s", i, cp);
|
|
cp += i-1;
|
|
}
|
|
first = 0;
|
|
}
|
|
}
|