e2fsprogs/e2fsck/message.c
Theodore Ts'o ecf1b7767e ChangeLog, journal.c, message.c, problem.c, problem.h, super.c:
journal.c (e2fsck_journal_load): Fix **nasty** bug which caused
  	e2fsck_check_ext3_journal to smash the journal because
  	journal->j_transaction_sequence wasn't getting initialized.
  journal.c: (recover_ext3_journal, e2fsck_run_ext3_journal): Move call
  	to e2fsck_clear_recover from recover_ext3_journal to after the
  	filesystem has been closed and reopened.  Otherwise, the superblock in
  	the filesystem handle will probably be stale, and will overwrite the
  	newer version of the superblock written by the log recovery.
  message.c (expand_inode_expression): Add support for %Iu and %Ig
  problem.h (PR_0_CLEAR_ORPHAN_INODE): Add new problem code.
  super.c (release_orphan_inodes, release_inode_block,
  	release_inode_blocks): Update the block group descriptor counts when
  	freeing the orphan inode.  Use PR_0_CLEAR_ORPHAN_INODE to report when
  	we clear an orphan.
  journal.c (e2fsck_run_ext3_journal): Fix a bug where we attempted to
  	reopen the filesystem using the device name instead of the filesystem
  	name.
2000-08-20 22:06:31 +00:00

439 lines
8.8 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
* %dt <dirent>->filetype
* %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
* %Iu <inode> -> i_uid
* %Ig <inode> -> i_gid
* %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
* %X <num> hexadecimal format
*
* The following '@' expansions are supported:
*
* @A error allocating
* @b block
* @B bitmap
* @c compress
* @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
* @o orphaned
* @r root inode
* @s should be
* @S superblock
* @u unattached
* @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[] = {
N_("Aerror allocating"),
N_("bblock"),
N_("Bbitmap"),
N_("ccompress"),
N_("Cconflicts with some other fs @b"),
N_("iinode"),
N_("Iillegal"),
N_("Ddeleted"),
N_("ddirectory"),
N_("eentry"),
N_("E@e '%Dn' in %p (%i)"),
N_("ffilesystem"),
N_("Ffor @i %i (%Q) is"),
N_("ggroup"),
N_("llost+found"),
N_("Lis a link"),
N_("oorphaned"),
N_("rroot @i"),
N_("sshould be"),
N_("Ssuper@b"),
N_("uunattached"),
N_("zzero-length"),
"@@",
0
};
/*
* Give more user friendly names to the "special" inodes.
*/
#define num_special_inodes 7
static const char *special_inode_name[] =
{
N_("<The NULL inode>"), /* 0 */
N_("<The bad blocks inode>"), /* 1 */
"/", /* 2 */
N_("<The ACL index inode>"), /* 3 */
N_("<The ACL data inode>"), /* 4 */
N_("<The boot loader inode>"), /* 5 */
N_("<The undelete directory inode>") /* 6 */
};
/*
* This function does "safe" printing. It will convert non-printable
* ASCII characters using '^' and M- notation.
*/
static void safe_print(const char *cp, int len)
{
unsigned char ch;
if (len < 0)
len = strlen(cp);
while (len--) {
ch = *cp++;
if (ch > 128) {
fputs("M-", stdout);
ch -= 128;
}
if ((ch < 32) || (ch == 0x7f)) {
fputc('^', stdout);
ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
}
fputc(ch, stdout);
}
}
/*
* 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 {
safe_print(path, -1);
ext2fs_free_mem((void **) &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 '%IX' 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':
if (LINUX_S_ISDIR(inode->i_mode))
printf("%u", inode->i_size);
else {
#ifdef EXT2_NO_64_TYPE
if (inode->i_size_high)
printf("0x%x%08x", inode->i_size_high,
inode->i_size);
else
printf("%u", inode->i_size);
#else
printf("%llu", (inode->i_size |
((__u64) inode->i_size_high << 32)));
#endif
}
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", (LINUX_S_ISDIR(inode->i_mode) ?
inode->i_dir_acl : 0));
break;
case 'u':
printf("%d", (inode->i_uid |
(inode->osd2.linux2.l_i_uid_high << 16)));
break;
case 'g':
printf("%d", (inode->i_gid |
(inode->osd2.linux2.l_i_gid_high << 16)));
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 & 0xFF;
if (len > EXT2_NAME_LEN)
len = EXT2_NAME_LEN;
if (len > dirent->rec_len)
len = dirent->rec_len;
safe_print(dirent->name, len);
break;
case 'r':
printf("%u", dirent->rec_len);
break;
case 'l':
printf("%u", dirent->name_len & 0xFF);
break;
case 't':
printf("%u", dirent->name_len >> 8);
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':
#ifdef EXT2_NO_64_TYPE
printf("%d", ctx->blkcount);
#else
printf("%lld", ctx->blkcount);
#endif
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':
#ifdef EXT2_NO_64_TYPE
printf("%u", ctx->num);
#else
printf("%llu", ctx->num);
#endif
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;
case 'X':
#ifdef EXT2_NO_64_TYPE
printf("0x%x", ctx->num);
#else
printf("0x%llx", ctx->num);
#endif
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;
e2fsck_clear_progbar(ctx);
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;
}
}