Whamcloud - gitweb
Enhance debugfs so that set_super_value can now set the wtime, mtime,
authorTheodore Ts'o <tytso@mit.edu>
Wed, 22 Dec 2004 01:37:36 +0000 (20:37 -0500)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 22 Dec 2004 01:37:36 +0000 (20:37 -0500)
lastcheck, and mkfs_time fields with date/time values.

Add the set_inode command to debugfs so that individual inode fields can
be more easily modified.  We should probably make the modify_inode
command go away at some point.

debugfs/ChangeLog
debugfs/Makefile.in
debugfs/debug_cmds.ct
debugfs/debugfs.8.in
debugfs/debugfs.h
debugfs/set_fields.c [moved from debugfs/setsuper.c with 51% similarity]

index 0b6c28f..d871262 100644 (file)
@@ -1,3 +1,12 @@
+2004-12-21  Theodore Ts'o  <tytso@mit.edu>
+
+       * setfields.c: Renamed from setsuper.c
+               Added support to set date/time fields.
+               Added support for setting superblock values wtime, mtime,
+                       lastcheck, and mkfs_time as date/time fields.
+               Added support for the set_inode command.
+       * debugfs.h, debug_cmds.ct, debugfs.8.in: Added set_inode command
+
 2004-12-16  Theodore Ts'o  <tytso@mit.edu>
 
        * setsuper.c: Add definitions for newer superblock fields:
index ccd32de..e0085c1 100644 (file)
@@ -18,11 +18,11 @@ MANPAGES=   debugfs.8
 MK_CMDS=       _SS_DIR_OVERRIDE=../lib/ss ../lib/ss/mk_cmds
 
 DEBUG_OBJS= debug_cmds.o debugfs.o util.o ncheck.o icheck.o ls.o \
-       lsdel.o dump.o setsuper.o logdump.o htree.o unused.o
+       lsdel.o dump.o set_fields.o logdump.o htree.o unused.o
 
 SRCS= debug_cmds.c $(srcdir)/debugfs.c $(srcdir)/util.c $(srcdir)/ls.c \
        $(srcdir)/ncheck.c $(srcdir)/icheck.c $(srcdir)/lsdel.c \
-       $(srcdir)/dump.c $(srcdir)/setsuper.c ${srcdir}/logdump.c \
+       $(srcdir)/dump.c $(srcdir)/set_fields.c ${srcdir}/logdump.c \
        $(srcdir)/htree.c $(srcdir)/unused.c
 
 LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBSS) $(LIBCOM_ERR) $(LIBBLKID) \
@@ -130,7 +130,7 @@ dump.o: $(srcdir)/dump.c $(srcdir)/debugfs.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/et/com_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
  $(top_srcdir)/lib/ext2fs/bitops.h
-setsuper.o: $(srcdir)/setsuper.c $(srcdir)/debugfs.h \
+set_fields.o: $(srcdir)/set_fields.c $(srcdir)/debugfs.h \
  $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \
  $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/et/com_err.h \
  $(top_srcdir)/lib/ext2fs/ext2_io.h $(top_builddir)/lib/ext2fs/ext2_err.h \
index cea5685..65ad998 100644 (file)
@@ -124,6 +124,9 @@ request do_rdump, "Recursively dump a directory to the native filesystem",
 request do_set_super, "Set superblock value",
        set_super_value, ssv;
 
+request do_set_inode, "Set inode field",
+       set_inode, si;
+
 request do_logdump, "Dump the contents of the journal",
        logdump;
 
index 9bb3354..b640bf9 100644 (file)
@@ -393,6 +393,17 @@ Mark inode
 .I filespec
 as in use in the inode bitmap.
 .TP
+.I set_inode filespec field value
+Modify the inode specified by 
+.I filespec
+so that the inode field
+.I field
+has value 
+.I value.
+The list of valid inode fields which can be set via this command 
+can be displayed by using the command:
+.B set_inode -l
+.TP
 .I set_super_value field value
 Set the superblock field
 .I field
index cb6ba85..b54f860 100644 (file)
@@ -70,8 +70,9 @@ extern void do_icheck(int argc, char **argv);
 /* ncheck.c */
 extern void do_ncheck(int argc, char **argv);
 
-/* set_super.c */
+/* set_fields.c */
 extern void do_set_super(int argc, char **);
+extern void do_set_inode(int argc, char **);
 
 /* unused.c */
 extern void do_dump_unused(int argc, char **argv);
similarity index 51%
rename from debugfs/setsuper.c
rename to debugfs/set_fields.c
index 60104a2..9cccceb 100644 (file)
@@ -1,5 +1,12 @@
 /*
- * setsuper.c --- set a superblock value
+ * set_fields.c --- set a superblock value
+ * 
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004 by Theodore Ts'o.
+ * 
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
  */
 
 #include <stdio.h>
 #include "e2p/e2p.h"
 
 static struct ext2_super_block set_sb;
+static struct ext2_inode set_inode;
 
-struct super_set_info {
+struct field_set_info {
        const char      *name;
        void    *ptr;
        unsigned int    size;
-       errcode_t (*func)(struct super_set_info *info, char *arg);
+       errcode_t (*func)(struct field_set_info *info, char *arg);
 };
 
-static errcode_t parse_uint(struct super_set_info *info, char *arg);
-static errcode_t parse_int(struct super_set_info *info, char *arg);
-static errcode_t parse_string(struct super_set_info *info, char *arg);
-static errcode_t parse_uuid(struct super_set_info *info, char *arg);
-static errcode_t parse_hashalg(struct super_set_info *info, char *arg);
+static errcode_t parse_uint(struct field_set_info *info, char *arg);
+static errcode_t parse_int(struct field_set_info *info, char *arg);
+static errcode_t parse_string(struct field_set_info *info, char *arg);
+static errcode_t parse_uuid(struct field_set_info *info, char *arg);
+static errcode_t parse_hashalg(struct field_set_info *info, char *arg);
+static errcode_t parse_time(struct field_set_info *info, char *arg);
 
-static struct super_set_info super_fields[] = {
+static struct field_set_info super_fields[] = {
        { "inodes_count", &set_sb.s_inodes_count, 4, parse_uint },
        { "blocks_count", &set_sb.s_blocks_count, 4, parse_uint },
        { "r_blocks_count", &set_sb.s_r_blocks_count, 4, parse_uint },
@@ -47,15 +56,15 @@ static struct super_set_info super_fields[] = {
        { "blocks_per_group", &set_sb.s_blocks_per_group, 4, parse_uint },
        { "frags_per_group", &set_sb.s_frags_per_group, 4, parse_uint },
        { "inodes_per_group", &set_sb.s_inodes_per_group, 4, parse_uint },
-       /* s_mtime (time_t) */
-       /* s_wtime (time_t) */
+       { "mtime", &set_sb.s_mtime, 4, parse_time },
+       { "wtime", &set_sb.s_wtime, 4, parse_time },
        { "mnt_count", &set_sb.s_mnt_count, 2, parse_uint },
        { "max_mnt_count", &set_sb.s_max_mnt_count, 2, parse_int },
        /* s_magic */
        { "state", &set_sb.s_state, 2, parse_uint },
        { "errors", &set_sb.s_errors, 2, parse_uint },
        { "minor_rev_level", &set_sb.s_minor_rev_level, 2, parse_uint },
-       /* s_lastcheck (time_t) */
+       { "lastcheck", &set_sb.s_lastcheck, 4, parse_time },
        { "checkinterval", &set_sb.s_checkinterval, 4, parse_uint },
        { "creator_os", &set_sb.s_creator_os, 4, parse_uint },
        { "rev_level", &set_sb.s_rev_level, 4, parse_uint },
@@ -89,24 +98,67 @@ static struct super_set_info super_fields[] = {
        /* s_reserved_word_pad */
        { "default_mount_opts", &set_sb.s_default_mount_opts, 4, parse_uint },
        { "first_meta_bg", &set_sb.s_first_meta_bg, 4, parse_uint },
-       { "mkfs_time", &set_sb.s_mkfs_time, 4, parse_uint },
+       { "mkfs_time", &set_sb.s_mkfs_time, 4, parse_time },
        { 0, 0, 0, 0 }
 };
 
-static struct super_set_info *find_field(char *field)
+static struct field_set_info inode_fields[] = {
+       { "inodes_count", &set_sb.s_inodes_count, 4, parse_uint },
+       { "mode", &set_inode.i_mode, 2, parse_uint },
+       { "uid", &set_inode.i_uid, 2, parse_uint },
+       { "size", &set_inode.i_uid, 4, parse_uint },
+       { "atime", &set_inode.i_atime, 4, parse_time },
+       { "ctime", &set_inode.i_ctime, 4, parse_time },
+       { "mtime", &set_inode.i_mtime, 4, parse_time },
+       { "dtime", &set_inode.i_dtime, 4, parse_time },
+       { "gid", &set_inode.i_gid, 2, parse_uint },
+       { "links_count", &set_inode.i_links_count, 2, parse_uint },
+       { "blocks", &set_inode.i_blocks, 4, parse_uint },
+       { "flags", &set_inode.i_flags, 4, parse_uint },
+       { "translator", &set_inode.osd1.hurd1.h_i_translator, 4, parse_uint },
+       { "block[0]", &set_inode.i_block[0], 4, parse_uint },
+       { "block[1]", &set_inode.i_block[1], 4, parse_uint },
+       { "block[2]", &set_inode.i_block[2], 4, parse_uint },
+       { "block[3]", &set_inode.i_block[3], 4, parse_uint },
+       { "block[4]", &set_inode.i_block[4], 4, parse_uint },
+       { "block[5]", &set_inode.i_block[5], 4, parse_uint },
+       { "block[6]", &set_inode.i_block[6], 4, parse_uint },
+       { "block[7]", &set_inode.i_block[7], 4, parse_uint },
+       { "block[8]", &set_inode.i_block[8], 4, parse_uint },
+       { "block[9]", &set_inode.i_block[9], 4, parse_uint },
+       { "block[10]", &set_inode.i_block[10], 4, parse_uint },
+       { "block[11]", &set_inode.i_block[11], 4, parse_uint },
+       { "block[12]", &set_inode.i_block[12], 4, parse_uint },
+       { "block[13]", &set_inode.i_block[13], 4, parse_uint },
+       { "block[14]", &set_inode.i_block[14], 4, parse_uint },
+       { "generation", &set_inode.i_generation, 4, parse_uint },
+       { "file_acl", &set_inode.i_file_acl, 4, parse_uint },
+       { "dir_acl", &set_inode.i_dir_acl, 4, parse_uint },
+       { "faddr", &set_inode.i_faddr, 4, parse_uint },
+       { "frag", &set_inode.osd2.linux2.l_i_frag, 8, parse_uint },
+       { "fsize", &set_inode.osd2.linux2.l_i_fsize, 8, parse_uint },
+       { "uid_high", &set_inode.osd2.linux2.l_i_uid_high, 8, parse_uint },
+       { "gid_high", &set_inode.osd2.linux2.l_i_gid_high, 8, parse_uint },
+       { "author", &set_inode.osd2.hurd2.h_i_author, 8, parse_uint },
+       { 0, 0, 0, 0 }
+};
+
+
+static struct field_set_info *find_field(struct field_set_info *fields,
+                                        char *field)
 {
-       struct super_set_info *ss;
+       struct field_set_info *ss;
 
        if (strncmp(field, "s_", 2) == 0)
                field += 2;
-       for (ss = super_fields ; ss->name ; ss++) {
+       for (ss = fields ; ss->name ; ss++) {
                if (strcmp(ss->name, field) == 0)
                        return ss;
        }
        return NULL;
 }
 
-static errcode_t parse_uint(struct super_set_info *info, char *arg)
+static errcode_t parse_uint(struct field_set_info *info, char *arg)
 {
        unsigned long   num;
        char *tmp;
@@ -137,7 +189,7 @@ static errcode_t parse_uint(struct super_set_info *info, char *arg)
        return 0;
 }
 
-static errcode_t parse_int(struct super_set_info *info, char *arg)
+static errcode_t parse_int(struct field_set_info *info, char *arg)
 {
        long    num;
        char *tmp;
@@ -168,7 +220,7 @@ static errcode_t parse_int(struct super_set_info *info, char *arg)
        return 0;
 }
 
-static errcode_t parse_string(struct super_set_info *info, char *arg)
+static errcode_t parse_string(struct field_set_info *info, char *arg)
 {
        char    *cp = (char *) info->ptr;
 
@@ -181,7 +233,39 @@ static errcode_t parse_string(struct super_set_info *info, char *arg)
        return 0;
 }
 
-static errcode_t parse_uuid(struct super_set_info *info, char *arg)
+static errcode_t parse_time(struct field_set_info *info, char *arg)
+{
+       struct  tm      ts;
+       __u32           *ptr32;
+
+       ptr32 = (__u32 *) info->ptr;
+
+       if (strcmp(arg, "now") == 0) {
+               *ptr32 = time(0);
+               return 0;
+       }
+       memset(&ts, 0, sizeof(ts));
+#ifdef HAVE_STRPTIME
+       strptime(arg, "%Y%m%d%H%M%S", &ts);
+#else
+       sscanf(arg, "%4d%2d%2d%2d%2d%2d", &ts.tm_year, &ts.tm_mon,
+              &ts.tm_mday, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
+       ts.tm_year -= 1900;
+       ts.tm_mon -= 1;
+       if (ts.tm_year < 0 || ts.tm_mon < 0 || ts.tm_mon > 11 ||
+           ts.tm_mday < 0 || ts.tm_mday > 31 || ts.tm_hour > 23 ||
+           ts.tm_min > 59 || ts.tm_sec > 61)
+               ts.tm_mday = 0;
+#endif
+       if (ts.tm_mday == 0) {
+               /* Try it as an integer... */
+               return parse_uint(info, arg);
+       }
+       *ptr32 = mktime(&ts);
+       return 0;
+}
+
+static errcode_t parse_uuid(struct field_set_info *info, char *arg)
 {
        unsigned char * p = (unsigned char *) info->ptr;
        
@@ -199,7 +283,7 @@ static errcode_t parse_uuid(struct super_set_info *info, char *arg)
        return 0;
 }
 
-static errcode_t parse_hashalg(struct super_set_info *info, char *arg)
+static errcode_t parse_hashalg(struct field_set_info *info, char *arg)
 {
        int     hashv;
        unsigned char   *p = (unsigned char *) info->ptr;
@@ -214,13 +298,24 @@ static errcode_t parse_hashalg(struct super_set_info *info, char *arg)
 }
 
 
-static void print_possible_fields(void)
+static void print_possible_fields(struct field_set_info *fields)
 {
-       struct super_set_info *ss;
-       const char      *type;
+       struct field_set_info *ss;
+       const char      *type, *cmd;
+       FILE *f;
 
-       printf("Superblock fields supported by the set_super_value command:\n");
-       for (ss = super_fields ; ss->name ; ss++) {
+       if (fields == super_fields) {
+               type = "Superblock";
+               cmd = "set_super_value";
+       } else {
+               type = "Inode";
+               cmd = "set_inode";
+       }
+       f = open_pager();
+
+       fprintf(f, "%s fields supported by the %s command:\n", type, cmd);
+
+       for (ss = fields ; ss->name ; ss++) {
                type = "unknown";
                if (ss->func == parse_string)
                        type = "string";
@@ -232,8 +327,11 @@ static void print_possible_fields(void)
                        type = "UUID";
                else if (ss->func == parse_hashalg)
                        type = "hash algorithm";
-               printf("\t%-20s\t%s\n", ss->name, type);
+               else if (ss->func == parse_time)
+                       type = "date/time";
+               fprintf(f, "\t%-20s\t%s\n", ss->name, type);
        }
+       close_pager(f);
 }
 
 
@@ -242,10 +340,10 @@ void do_set_super(int argc, char *argv[])
        const char *usage = "<field> <value>\n"
                "\t\"set_super_value -l\" will list the names of "
                "superblock fields\n\twhich can be set.";
-       static struct super_set_info *ss;
+       static struct field_set_info *ss;
        
        if ((argc == 2) && !strcmp(argv[1], "-l")) {
-               print_possible_fields();
+               print_possible_fields(super_fields);
                return;
        }
 
@@ -253,7 +351,7 @@ void do_set_super(int argc, char *argv[])
                                usage, CHECK_FS_RW))
                return;
 
-       if ((ss = find_field(argv[1])) == 0) {
+       if ((ss = find_field(super_fields, argv[1])) == 0) {
                com_err(argv[0], 0, "invalid field specifier: %s", argv[1]);
                return;
        }
@@ -263,3 +361,38 @@ void do_set_super(int argc, char *argv[])
                ext2fs_mark_super_dirty(current_fs);
        }
 }
+
+void do_set_inode(int argc, char *argv[])
+{
+       const char *usage = "<inode> <field> <value>\n"
+               "\t\"set_inode -l\" will list the names of "
+               "the fields in an ext2 inode\n\twhich can be set.";
+       static struct field_set_info *ss;
+       ext2_ino_t ino;
+       
+       if ((argc == 2) && !strcmp(argv[1], "-l")) {
+               print_possible_fields(inode_fields);
+               return;
+       }
+
+       if (common_args_process(argc, argv, 4, 4, "set_inode",
+                               usage, CHECK_FS_RW))
+               return;
+
+       if ((ss = find_field(inode_fields, argv[2])) == 0) {
+               com_err(argv[0], 0, "invalid field specifier: %s", argv[2]);
+               return;
+       }
+
+       ino = string_to_inode(argv[1]);
+       if (!ino)
+               return;
+
+       if (debugfs_read_inode(ino, &set_inode, argv[1]))
+               return;
+
+       if (ss->func(ss, argv[3]) == 0) {
+               if (debugfs_write_inode(ino, &set_inode, argv[1]))
+                       return;
+       }
+}