Whamcloud - gitweb
debugfs: dump "fid" and "lma" xattrs on inode stat
[tools/e2fsprogs.git] / debugfs / xattrs.c
index 92bd4e5..e1b0459 100644 (file)
@@ -17,6 +17,7 @@ extern char *optarg;
 #include "support/cstring.h"
 
 #include "debugfs.h"
+#include "ext2fs/lfsck.h"
 
 #define PRINT_XATTR_HEX                0x01
 #define PRINT_XATTR_RAW                0x02
@@ -24,6 +25,8 @@ extern char *optarg;
 #define PRINT_XATTR_STATFMT    0x08
 #define PRINT_XATTR_NOQUOTES   0x10
 
+extern const char *debug_prog_name;
+
 /* Dump extended attributes */
 static void print_xattr_hex(FILE *f, const char *str, int len)
 {
@@ -81,12 +84,106 @@ static void print_xattr(FILE *f, char *name, char *value, size_t value_len,
        fputc('\n', f);
 }
 
-static int dump_attr(char *name, char *value, size_t value_len, void *data)
+static void print_fidstr(FILE *f, void *name, void *value,
+                        ext2_ino_t inode_num, size_t value_len)
+{
+       struct filter_fid_old *ff = value;
+       int stripe;
+
+       /* Since Lustre 2.4 only the parent FID is stored in filter_fid,
+        * and the self fid is stored in the LMA and is printed below. */
+       if (value_len < sizeof(ff->ff_parent)) {
+               fprintf(stderr, "%s: error: filter_fid for inode %u smaller "
+                       "than expected (%lu bytes).\n",
+                       debug_prog_name, inode_num, value_len);
+               return;
+       }
+       fid_le_to_cpu(&ff->ff_parent, &ff->ff_parent);
+       stripe = fid_ver(&ff->ff_parent); /* stripe index is stored in f_ver */
+       ff->ff_parent.f_ver = 0;
+
+       fprintf(f, "  fid: ");
+       /* Old larger filter_fid should only ever be used with seq = 0.
+        * FID-on-OST should use LMA for FID_SEQ_NORMAL OST objects. */
+       if (value_len == sizeof(*ff))
+               fprintf(f, "objid=%llu seq=%llu ",
+                       ext2fs_le64_to_cpu(ff->ff_objid),
+                       ext2fs_le64_to_cpu(ff->ff_seq));
+
+       fprintf(f, "parent="DFID" stripe=%u", PFID(&ff->ff_parent), stripe);
+       if (value_len > sizeof(*ff)) {
+               struct filter_fid *ff_new = value;
+
+               fprintf(f, " stripe_size=%u stripe_count=%u",
+                       ext2fs_le32_to_cpu(ff_new->ff_stripe_size),
+                       ext2fs_le32_to_cpu(ff_new->ff_stripe_count));
+               if (ff_new->ff_pfl_id != 0)
+                       fprintf(f, " component_id=%u component_start=%llu "
+                               "component_end=%llu",
+                               ext2fs_le32_to_cpu(ff_new->ff_pfl_id),
+                               ext2fs_le64_to_cpu(ff_new->ff_pfl_start),
+                               ext2fs_le64_to_cpu(ff_new->ff_pfl_end));
+       }
+       fprintf(f, "\n");
+}
+
+static void print_lmastr(FILE *f, void *name, void *value,
+                        ext2_ino_t inode_num, size_t value_len)
+{
+       struct lustre_mdt_attrs *lma = value;
+       struct lustre_ost_attrs *loa = value;
+
+       if (value_len < offsetof(typeof(*lma), lma_self_fid) +
+                       sizeof(lma->lma_self_fid)) {
+               fprintf(stderr, "%s: error: LMA for inode %u smaller than "
+                       "expected (%lu bytes).\n",
+                       debug_prog_name, inode_num, value_len);
+               return;
+       }
+       fid_le_to_cpu(&lma->lma_self_fid, &lma->lma_self_fid);
+       fprintf(f, "  lma: fid="DFID" compat=%x incompat=%x\n",
+               PFID(&lma->lma_self_fid), ext2fs_le32_to_cpu(lma->lma_compat),
+               ext2fs_le32_to_cpu(lma->lma_incompat));
+       if (value_len >= offsetof(typeof(*loa), loa_pfl_end) +
+                 sizeof(loa->loa_pfl_end)) {
+               int idx;
+               int cnt;
+
+               fid_le_to_cpu(&loa->loa_parent_fid, &loa->loa_parent_fid);
+               idx = loa->loa_parent_fid.f_ver & PFID_STRIPE_COUNT_MASK;
+               cnt = loa->loa_parent_fid.f_ver >> PFID_STRIPE_IDX_BITS;
+               loa->loa_parent_fid.f_ver = 0;
+
+               fprintf(f, "  fid: parent="DFID" stripe=%u stripe_size=%u "
+                       "stripe_count=%u", PFID(&loa->loa_parent_fid), idx,
+                       ext2fs_le32_to_cpu(loa->loa_stripe_size), cnt);
+               if (loa->loa_pfl_id != 0)
+                       fprintf(f, " component_id=%u component_start=%llu "
+                               "component_end=%llu",
+                               ext2fs_le32_to_cpu(loa->loa_pfl_id),
+                               ext2fs_le64_to_cpu(loa->loa_pfl_start),
+                               ext2fs_le64_to_cpu(loa->loa_pfl_end));
+               fprintf(f, "\n");
+       }
+}
+
+static int dump_attr(char *name, char *value, size_t value_len,
+                    ext2_ino_t inode_num, void *data)
 {
        FILE *out = data;
 
        fprintf(out, "  ");
        print_xattr(out, name, value, value_len, PRINT_XATTR_STATFMT);
+       if (!strncmp(name, EXT2_ATTR_INDEX_TRUSTED_PREFIX LUSTRE_XATTR_OST_FID,
+                    strlen(name)) ||
+           !strncmp(name, EXT2_ATTR_INDEX_LUSTRE_PREFIX LUSTRE_XATTR_OST_FID,
+                    strlen(name)))
+               print_fidstr(out, name, value, inode_num, value_len);
+       if (!strncmp(name, EXT2_ATTR_INDEX_TRUSTED_PREFIX LUSTRE_XATTR_MDT_LMA,
+                    strlen(name)) ||
+           !strncmp(name, EXT2_ATTR_INDEX_LUSTRE_PREFIX LUSTRE_XATTR_MDT_LMA,
+                    strlen(name)))
+               print_lmastr(out, name, value, inode_num, value_len);
        return 0;
 }
 
@@ -306,13 +403,6 @@ void do_set_xattr(int argc, char **argv)
        }
 
        err = ext2fs_xattr_set(h, argv[optind + 1], buf, buflen);
-       if (err)
-               goto out;
-
-       err = ext2fs_xattrs_write(h);
-       if (err)
-               goto out;
-
 out:
        ext2fs_xattrs_close(&h);
        if (err)
@@ -360,12 +450,147 @@ void do_rm_xattr(int argc, char **argv)
                if (err)
                        goto out;
        }
-
-       err = ext2fs_xattrs_write(h);
-       if (err)
-               goto out;
 out:
        ext2fs_xattrs_close(&h);
        if (err)
                com_err(argv[0], err, "while removing extended attribute");
 }
+
+/*
+ * Return non-zero if the string has a minimal number of non-printable
+ * characters.
+ */
+static int is_mostly_printable(const char *cp, int len)
+{
+       int     np = 0;
+
+       if (len < 0)
+               len = strlen(cp);
+
+       while (len--) {
+               if (!isprint(*cp++)) {
+                       np++;
+                       if (np > 3)
+                               return 0;
+               }
+       }
+       return 1;
+}
+
+static void safe_print(FILE *f, const char *cp, int len)
+{
+       unsigned char   ch;
+
+       if (len < 0)
+               len = strlen(cp);
+
+       while (len--) {
+               ch = *cp++;
+               if (ch > 128) {
+                       fputs("M-", f);
+                       ch -= 128;
+               }
+               if ((ch < 32) || (ch == 0x7f)) {
+                       fputc('^', f);
+                       ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
+               }
+               fputc(ch, f);
+       }
+}
+
+static void dump_xattr_raw_entries(FILE *f, unsigned char *buf,
+                                  unsigned int start, unsigned int len,
+                                  unsigned value_start)
+{
+       struct ext2_ext_attr_entry ent;
+       unsigned int off = start;
+       unsigned int vstart;
+
+       while (off < len) {
+               if ((*(__u16 *) (buf + off)) == 0) {
+                       fprintf(f, "last entry found at offset %u (%04o)\n",
+                               off, off);
+                       break;
+               }
+               if ((off + sizeof(struct ext2_ext_attr_entry)) >= len) {
+                       fprintf(f, "xattr buffer overrun at %u (len = %u)\n",
+                               off, len);
+                       break;
+               }
+#if WORDS_BIGENDIAN
+               ext2fs_swap_ext_attr_entry(&ent,
+                       (struct ext2_ext_attr_entry *) (buf + off));
+#else
+               ent = *((struct ext2_ext_attr_entry *) (buf + off));
+#endif
+               fprintf(f, "offset = %d (%04o), name_len = %u, "
+                       "name_index = %u\n",
+                       off, off, ent.e_name_len, ent.e_name_index);
+               vstart = value_start + ent.e_value_offs;
+               fprintf(f, "value_offset = %d (%04o), value_inum = %u, "
+                       "value_size = %u\n", ent.e_value_offs,
+                       vstart, ent.e_value_inum, ent.e_value_size);
+               off += sizeof(struct ext2_ext_attr_entry);
+               fprintf(f, "name = ");
+               if ((off + ent.e_name_len) >= len)
+                       fprintf(f, "<runs off end>");
+               else
+                       safe_print(f, (char *)(buf + off), ent.e_name_len);
+               fputc('\n', f);
+               if (ent.e_value_size == 0)
+                       goto skip_value;
+               fprintf(f, "value = ");
+               if (ent.e_value_inum)
+                       fprintf(f, "<ino %u>", ent.e_value_inum);
+               else if (ent.e_value_offs >= len ||
+                        (vstart + ent.e_value_size) > len)
+                       fprintf(f, "<runs off end>");
+               if (is_mostly_printable((char *)(buf + vstart),
+                                       ent.e_value_size))
+                       safe_print(f, (char *)(buf + vstart),
+                                  ent.e_value_size);
+               else {
+                       fprintf(f, "<hexdump>\n");
+                       do_byte_hexdump(f, (unsigned char *)(buf + vstart),
+                                       ent.e_value_size);
+               }
+               fputc('\n', f);
+       skip_value:
+               fputc('\n', f);
+               off += (ent.e_name_len + 3) & ~3;
+       }
+}
+
+void raw_inode_xattr_dump(FILE *f, unsigned char *buf, unsigned int len)
+{
+       __u32 magic = ext2fs_le32_to_cpu(*((__le32 *) buf));
+
+       fprintf(f, "magic = %08x, length = %u, value_start =4 \n\n",
+               magic, len);
+       if (magic == EXT2_EXT_ATTR_MAGIC)
+               dump_xattr_raw_entries(f, buf, 4, len, 4);
+}
+
+void block_xattr_dump(FILE *f, unsigned char *buf, unsigned int len)
+{
+       struct ext2_ext_attr_header header;
+
+#ifdef WORDS_BIGENDIAN
+       ext2fs_swap_ext_attr_header(&header,
+                                   (struct ext2_ext_attr_header *) buf);
+#else
+       header = *((struct ext2_ext_attr_header *) buf);
+#endif
+       fprintf(f, "magic = %08x, length = %u\n", header.h_magic, len);
+       if (header.h_magic != EXT2_EXT_ATTR_MAGIC)
+               return;
+       fprintf(f, "refcount = %u, blocks = %u\n", header.h_refcount,
+               header.h_blocks);
+       fprintf(f, "hash = %08x, checksum = %08x\n", header.h_hash,
+               header.h_checksum);
+       fprintf(f, "reserved: %08x %08x %08x\n\n", header.h_reserved[0],
+               header.h_reserved[1], header.h_reserved[2]);
+
+       dump_xattr_raw_entries(f, buf,
+                              sizeof(struct ext2_ext_attr_header), len, 0);
+}