aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Dilger <adilger@sun.com>2008-08-23 21:42:46 -0600
committerTheodore Ts'o <tytso@mit.edu>2008-08-24 21:31:52 -0400
commit03efde8abe79c80ff369206d06d4f1e476b08f53 (patch)
tree38fbb40a61b67a044cae622b79e5545af994aeb7
parent28b74daa10bfd4e6d908ca030a9d9c5b8269a26c (diff)
downloade2fsprogs-03efde8abe79c80ff369206d06d4f1e476b08f53.tar.gz
add debugfs command to print known features
Print out the currently supported features of e2fsprogs/libext2fs via a new "debugfs supported_features" command. This helps scripts to know whether it is possible to try and enable specific features in the filesystem. Signed-off-by: Kalpak Shah <kalpak.shah@sun.com> Signed-off-by: Andreas Dilger <adilger@sun.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--debugfs/debug_cmds.ct3
-rw-r--r--debugfs/debugfs.c66
-rw-r--r--lib/e2p/Makefile.in10
-rw-r--r--lib/e2p/e2p.h3
-rw-r--r--lib/e2p/feature.c130
5 files changed, 210 insertions, 2 deletions
diff --git a/debugfs/debug_cmds.ct b/debugfs/debug_cmds.ct
index a4a5a4c1..59314b81 100644
--- a/debugfs/debug_cmds.ct
+++ b/debugfs/debug_cmds.ct
@@ -154,5 +154,8 @@ request do_dump_unused, "Dump unused blocks",
request do_set_current_time, "Set current time to use when setting filesystme fields",
set_current_time;
+request do_supported_features, "Print features supported by this version of e2fsprogs",
+ supported_features;
+
end;
diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
index 935df812..620a513c 100644
--- a/debugfs/debugfs.c
+++ b/debugfs/debugfs.c
@@ -36,6 +36,7 @@ extern char *optarg;
#include <ext2fs/ext2_ext_attr.h>
#include "../version.h"
+#include "jfs_user.h"
extern ss_request_table debug_cmds;
ss_request_table *extra_cmds;
@@ -1806,6 +1807,71 @@ void do_set_current_time(int argc, char *argv[])
}
}
+static int find_supp_feature(__u32 *supp, int feature_type, char *name)
+{
+ int compat, bit, ret;
+ unsigned int feature_mask;
+
+ if (name) {
+ if (feature_type == E2P_FS_FEATURE)
+ ret = e2p_string2feature(name, &compat, &feature_mask);
+ else
+ ret = e2p_jrnl_string2feature(name, &compat,
+ &feature_mask);
+ if (ret)
+ return ret;
+
+ if (!(supp[compat] & feature_mask))
+ return 1;
+ } else {
+ for (compat = 0; compat < 3; compat++) {
+ for (bit = 0, feature_mask = 1; bit < 32;
+ bit++, feature_mask <<= 1) {
+ if (supp[compat] & feature_mask) {
+ if (feature_type == E2P_FS_FEATURE)
+ fprintf(stdout, " %s",
+ e2p_feature2string(compat,
+ feature_mask));
+ else
+ fprintf(stdout, " %s",
+ e2p_jrnl_feature2string(compat,
+ feature_mask));
+ }
+ }
+ }
+ fprintf(stdout, "\n");
+ }
+
+ return 0;
+}
+
+void do_supported_features(int argc, char *argv[])
+{
+ int i, j, ret;
+ __u32 supp[3] = { EXT2_LIB_FEATURE_COMPAT_SUPP,
+ EXT2_LIB_FEATURE_INCOMPAT_SUPP,
+ EXT2_LIB_FEATURE_RO_COMPAT_SUPP };
+ __u32 jrnl_supp[3] = { JFS_KNOWN_COMPAT_FEATURES,
+ JFS_KNOWN_INCOMPAT_FEATURES,
+ JFS_KNOWN_ROCOMPAT_FEATURES };
+
+ if (argc > 1) {
+ ret = find_supp_feature(supp, E2P_FS_FEATURE, argv[1]);
+ if (ret) {
+ ret = find_supp_feature(jrnl_supp, E2P_JOURNAL_FEATURE,
+ argv[1]);
+ }
+ if (ret)
+ com_err(argv[0], 0, "Unknown feature: %s\n", argv[1]);
+ else
+ fprintf(stdout, "Supported feature: %s\n", argv[1]);
+ } else {
+ fprintf(stdout, "Supported features:");
+ ret = find_supp_feature(supp, E2P_FS_FEATURE, NULL);
+ ret = find_supp_feature(jrnl_supp, E2P_JOURNAL_FEATURE, NULL);
+ }
+}
+
static int source_file(const char *cmd_file, int sci_idx)
{
FILE *f;
diff --git a/lib/e2p/Makefile.in b/lib/e2p/Makefile.in
index 65574802..2c56ab5f 100644
--- a/lib/e2p/Makefile.in
+++ b/lib/e2p/Makefile.in
@@ -69,8 +69,14 @@ tst_ostype: $(srcdir)/ostype.c
@$(CC) -DTEST_PROGRAM -I$(top_srcdir)/lib -o tst_ostype \
$(srcdir)/ostype.c $(ALL_CFLAGS)
-check:: tst_ostype
+tst_feature: $(srcdir)/feature.c
+ @echo " LD $@"
+ @$(CC) -DTEST_PROGRAM -I$(top_srcdir)/lib -o tst_feature \
+ $(srcdir)/feature.c $(ALL_CFLAGS)
+
+check:: tst_ostype tst_feature
./tst_ostype
+ ./tst_feature
installdirs::
@echo " MKINSTALLDIRS $(libdir) $(includedir)/e2p"
@@ -96,7 +102,7 @@ uninstall::
clean::
$(RM) -f \#* *.s *.o *.a *~ *.bak core profiled/* checker/*
- $(RM) -f ../libe2p.a ../libe2p_p.a tst_ostype
+ $(RM) -f ../libe2p.a ../libe2p_p.a tst_ostype tst_feature
mostlyclean:: clean
distclean:: clean
diff --git a/lib/e2p/e2p.h b/lib/e2p/e2p.h
index 06e2120d..ad607f68 100644
--- a/lib/e2p/e2p.h
+++ b/lib/e2p/e2p.h
@@ -11,6 +11,9 @@
#define E2P_FEATURE_NEGATE_FLAG 0x80
+#define E2P_FS_FEATURE 0
+#define E2P_JOURNAL_FEATURE 1
+
/* `options' for print_flags() */
#define PFOPT_LONG 1 /* Must be 1 for compatibility with `int long_format'. */
diff --git a/lib/e2p/feature.c b/lib/e2p/feature.c
index 12cb8a32..e3a72047 100644
--- a/lib/e2p/feature.c
+++ b/lib/e2p/feature.c
@@ -15,6 +15,8 @@
#include <errno.h>
#include "e2p.h"
+#include <ext2fs/ext2fs.h>
+#include <ext2fs/jfs_user.h>
struct feature {
int compat;
@@ -74,6 +76,17 @@ static struct feature feature_list[] = {
{ 0, 0, 0 },
};
+static struct feature jrnl_feature_list[] = {
+ { E2P_FEATURE_COMPAT, JFS_FEATURE_COMPAT_CHECKSUM,
+ "journal_checksum" },
+
+ { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_REVOKE,
+ "journal_incompat_revoke" },
+ { E2P_FEATURE_INCOMPAT, JFS_FEATURE_INCOMPAT_ASYNC_COMMIT,
+ "journal_async_commit" },
+ { 0, 0, 0 },
+};
+
const char *e2p_feature2string(int compat, unsigned int mask)
{
struct feature *f;
@@ -148,6 +161,79 @@ int e2p_string2feature(char *string, int *compat_type, unsigned int *mask)
return 0;
}
+const char *e2p_jrnl_feature2string(int compat, unsigned int mask)
+{
+ struct feature *f;
+ static char buf[20];
+ char fchar;
+ int fnum;
+
+ for (f = jrnl_feature_list; f->string; f++) {
+ if ((compat == f->compat) &&
+ (mask == f->mask))
+ return f->string;
+ }
+ switch (compat) {
+ case E2P_FEATURE_COMPAT:
+ fchar = 'C';
+ break;
+ case E2P_FEATURE_INCOMPAT:
+ fchar = 'I';
+ break;
+ case E2P_FEATURE_RO_INCOMPAT:
+ fchar = 'R';
+ break;
+ default:
+ fchar = '?';
+ break;
+ }
+ for (fnum = 0; mask >>= 1; fnum++);
+ sprintf(buf, "FEATURE_%c%d", fchar, fnum);
+ return buf;
+}
+
+int e2p_jrnl_string2feature(char *string, int *compat_type, unsigned int *mask)
+{
+ struct feature *f;
+ char *eptr;
+ int num;
+
+ for (f = jrnl_feature_list; f->string; f++) {
+ if (!strcasecmp(string, f->string)) {
+ *compat_type = f->compat;
+ *mask = f->mask;
+ return 0;
+ }
+ }
+ if (strncasecmp(string, "FEATURE_", 8))
+ return 1;
+
+ switch (string[8]) {
+ case 'c':
+ case 'C':
+ *compat_type = E2P_FEATURE_COMPAT;
+ break;
+ case 'i':
+ case 'I':
+ *compat_type = E2P_FEATURE_INCOMPAT;
+ break;
+ case 'r':
+ case 'R':
+ *compat_type = E2P_FEATURE_RO_INCOMPAT;
+ break;
+ default:
+ return 1;
+ }
+ if (string[9] == 0)
+ return 1;
+ num = strtol(string+9, &eptr, 10);
+ if (num > 32 || num < 0)
+ return 1;
+ if (*eptr)
+ return 1;
+ *mask = 1 << num;
+ return 0;
+}
static char *skip_over_blanks(char *cp)
{
while (*cp && isspace(*cp))
@@ -252,3 +338,47 @@ int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array)
{
return e2p_edit_feature2(str, compat_array, ok_array, 0, 0, 0);
}
+
+#ifdef TEST_PROGRAM
+int main(int argc, char **argv)
+{
+ int compat, compat2, i;
+ unsigned int mask, mask2;
+ const char *str;
+ struct feature *f;
+
+ for (i = 0; i < 2; i++) {
+ if (i == 0) {
+ f = feature_list;
+ printf("Feature list:\n");
+ } else {
+ printf("\nJournal feature list:\n");
+ f = jrnl_feature_list;
+ }
+ for (; f->string; f++) {
+ if (i == 0) {
+ e2p_string2feature((char *)f->string, &compat,
+ &mask);
+ str = e2p_feature2string(compat, mask);
+ } else {
+ e2p_jrnl_string2feature((char *)f->string,
+ &compat, &mask);
+ str = e2p_jrnl_feature2string(compat, mask);
+ }
+
+ printf("\tCompat = %d, Mask = %u, %s\n",
+ compat, mask, f->string);
+ if (strcmp(f->string, str)) {
+ if (e2p_string2feature((char *) str, &compat2,
+ &mask2) ||
+ (compat2 != compat) ||
+ (mask2 != mask)) {
+ fprintf(stderr, "Failure!\n");
+ exit(1);
+ }
+ }
+ }
+ }
+ exit(0);
+}
+#endif