2 * xattrs.c --- Modify extended attributes via debugfs.
4 * Copyright (C) 2014 Oracle. This file may be redistributed
5 * under the terms of the GNU Public License.
17 #include "support/cstring.h"
20 #include "ext2fs/ext4_acl.h"
21 #include "ext2fs/lfsck.h"
23 #define PRINT_XATTR_HEX 0x01
24 #define PRINT_XATTR_RAW 0x02
25 #define PRINT_XATTR_C 0x04
26 #define PRINT_XATTR_STATFMT 0x08
27 #define PRINT_XATTR_NOQUOTES 0x10
29 extern const char *debug_prog_name;
31 /* Dump extended attributes */
32 static void print_xattr_hex(FILE *f, const char *str, int len)
36 for (i = 0; i < len; i++)
37 fprintf(f, "%02x ", (unsigned char)str[i]);
40 /* Dump extended attributes */
41 static void print_xattr_string(FILE *f, const char *str, int len, int flags)
46 if (flags & PRINT_XATTR_RAW) {
47 fwrite(str, len, 1, f);
51 if ((flags & PRINT_XATTR_C) == 0) {
52 /* check: is string "printable enough?" */
53 for (i = 0; i < len; i++)
57 if (printable <= len*7/8)
58 flags |= PRINT_XATTR_HEX;
61 if (flags & PRINT_XATTR_HEX) {
62 print_xattr_hex(f, str, len);
64 if ((flags & PRINT_XATTR_NOQUOTES) == 0)
66 print_c_string(f, str, len);
67 if ((flags & PRINT_XATTR_NOQUOTES) == 0)
72 static void print_xattr(FILE *f, char *name, char *value, size_t value_len,
75 print_xattr_string(f, name, strlen(name), PRINT_XATTR_NOQUOTES);
76 fprintf(f, " (%zu)", value_len);
77 if ((print_flags & PRINT_XATTR_STATFMT) &&
78 (strcmp(name, "system.data") == 0))
81 (!(print_flags & PRINT_XATTR_STATFMT) || (value_len < 120))) {
83 print_xattr_string(f, value, value_len, print_flags);
88 static int print_acl(FILE *f, char *name, void *value, size_t value_len)
90 const ext4_acl_header *ext_acl = (const ext4_acl_header *)value;
94 (value_len < sizeof(ext4_acl_header)) ||
95 (ext_acl->a_version != ext2fs_cpu_to_le32(EXT4_ACL_VERSION)))
98 cp = (const char *)value + sizeof(ext4_acl_header);
99 value_len -= sizeof(ext4_acl_header);
101 fprintf(f, "%s:\n", name);
103 while (value_len > 0) {
104 const ext4_acl_entry *disk_entry = (const ext4_acl_entry *)cp;
105 posix_acl_xattr_entry entry;
106 entry.e_tag = ext2fs_le16_to_cpu(disk_entry->e_tag);
107 entry.e_perm = ext2fs_le16_to_cpu(disk_entry->e_perm);
109 switch(entry.e_tag) {
112 fprintf(f, " user:");
113 if (entry.e_tag == ACL_USER)
115 ext2fs_le32_to_cpu(disk_entry->e_id));
120 fprintf(f, " group:");
121 if (entry.e_tag == ACL_GROUP)
123 ext2fs_le32_to_cpu(disk_entry->e_id));
127 fprintf(f, " mask:");
131 fprintf(f, " other:");
136 "%s: error: invalid tag %x in ACL\n",
137 debug_prog_name, entry.e_tag);
141 fprintf(f, (entry.e_perm & ACL_READ) ? "r" : "-");
142 fprintf(f, (entry.e_perm & ACL_WRITE) ? "w" : "-");
143 fprintf(f, (entry.e_perm & ACL_EXECUTE) ? "x" : "-");
146 if (entry.e_tag == ACL_USER || entry.e_tag == ACL_GROUP) {
147 cp += sizeof(ext4_acl_entry);
148 value_len -= sizeof(ext4_acl_entry);
150 cp += sizeof(ext4_acl_entry_short);
151 value_len -= sizeof(ext4_acl_entry_short);
158 static int print_fidstr(FILE *f, char *name, void *value, size_t value_len)
160 struct filter_fid_old *ff = value;
163 /* Since Lustre 2.4 only the parent FID is stored in filter_fid,
164 * and the self fid is stored in the LMA and is printed below. */
165 if (value_len < sizeof(ff->ff_parent)) {
166 fprintf(stderr, "%s: error: xattr '%s' too small (%zu bytes)\n",
167 debug_prog_name, name, value_len);
170 fid_le_to_cpu(&ff->ff_parent, &ff->ff_parent);
171 stripe = fid_ver(&ff->ff_parent); /* stripe index is stored in f_ver */
172 ff->ff_parent.f_ver = 0;
175 /* Old larger filter_fid should only ever be used with seq = 0.
176 * FID-on-OST should use LMA for FID_SEQ_NORMAL OST objects. */
177 if (value_len == sizeof(*ff))
178 fprintf(f, "objid=%llu seq=%llu ",
179 ext2fs_le64_to_cpu(ff->ff_objid),
180 ext2fs_le64_to_cpu(ff->ff_seq));
182 fprintf(f, "parent="DFID" stripe=%u", PFID(&ff->ff_parent), stripe);
183 if (value_len >= sizeof(struct filter_fid_210)) {
184 struct filter_fid_210 *ff_new = value;
186 fprintf(f, " stripe_size=%u stripe_count=%u",
187 ext2fs_le32_to_cpu(ff_new->ff_stripe_size),
188 ext2fs_le32_to_cpu(ff_new->ff_stripe_count));
189 if (ff_new->ff_pfl_id != 0)
190 fprintf(f, " component_id=%u component_start=%llu "
191 "component_end=%llu",
192 ext2fs_le32_to_cpu(ff_new->ff_pfl_id),
193 ext2fs_le64_to_cpu(ff_new->ff_pfl_start),
194 ext2fs_le64_to_cpu(ff_new->ff_pfl_end));
197 if (value_len >= sizeof(struct filter_fid)) {
198 struct filter_fid *ff_new = value;
200 fprintf(f, " layout_version=%u range=%u",
201 ext2fs_le32_to_cpu(ff_new->ff_layout_version),
202 ext2fs_le32_to_cpu(ff_new->ff_range));
210 static int print_lmastr(FILE *f, char *name, void *value, size_t value_len)
212 struct lustre_mdt_attrs *lma = value;
213 struct lustre_ost_attrs *loa = value;
215 if (value_len < offsetof(typeof(*lma), lma_self_fid) +
216 sizeof(lma->lma_self_fid)) {
217 fprintf(stderr, "%s: error: xattr '%s' too small (%zu bytes)\n",
218 debug_prog_name, name, value_len);
221 fid_le_to_cpu(&lma->lma_self_fid, &lma->lma_self_fid);
222 fprintf(f, "lma: fid="DFID" compat=%x incompat=%x\n",
223 PFID(&lma->lma_self_fid), ext2fs_le32_to_cpu(lma->lma_compat),
224 ext2fs_le32_to_cpu(lma->lma_incompat));
225 if (value_len >= offsetof(typeof(*loa), loa_pfl_end) +
226 sizeof(loa->loa_pfl_end)) {
230 fid_le_to_cpu(&loa->loa_parent_fid, &loa->loa_parent_fid);
231 idx = loa->loa_parent_fid.f_ver & PFID_STRIPE_COUNT_MASK;
232 cnt = loa->loa_parent_fid.f_ver >> PFID_STRIPE_IDX_BITS;
233 loa->loa_parent_fid.f_ver = 0;
235 fprintf(f, " fid: parent="DFID" stripe=%u stripe_size=%u "
236 "stripe_count=%u", PFID(&loa->loa_parent_fid), idx,
237 ext2fs_le32_to_cpu(loa->loa_stripe_size), cnt);
238 if (loa->loa_pfl_id != 0)
239 fprintf(f, " component_id=%u component_start=%llu "
240 "component_end=%llu",
241 ext2fs_le32_to_cpu(loa->loa_pfl_id),
242 ext2fs_le64_to_cpu(loa->loa_pfl_start),
243 ext2fs_le64_to_cpu(loa->loa_pfl_end));
250 static void print_name(FILE *f, const char *cp, int len)
256 if (!isprint(ch) || ch == '\\') {
258 fprintf(f, "\\x%02x", ch);
266 static int print_linkea(FILE *f, char *name, void *value, size_t value_len)
268 struct link_ea_header *leh = value;
269 struct link_ea_entry *lee;
272 if (value_len < sizeof(*leh) ||
273 value_len < ext2fs_le64_to_cpu(leh->leh_len)) {
274 fprintf(stderr, "%s: error: xattr '%s' too small (%zu bytes)\n",
275 debug_prog_name, name, value_len);
279 if (ext2fs_le32_to_cpu(leh->leh_magic) != LINK_EA_MAGIC) {
280 fprintf(stderr, "%s: error: xattr '%s' bad magic '%#x'\n",
281 debug_prog_name, name,
282 ext2fs_le32_to_cpu(leh->leh_magic));
286 lee = leh->leh_entry;
287 value_len -= sizeof(*leh);
289 for (i = 0; i < ext2fs_le32_to_cpu(leh->leh_reccount) &&
290 value_len > 2; i++) {
291 int reclen = lee->lee_reclen[0] << 8 | lee->lee_reclen[1];
294 if (value_len < sizeof(*lee) || value_len < reclen) {
296 "%s: error: xattr '%s' entry %d too small "
298 debug_prog_name, name, i, value_len);
302 memcpy(&pfid, &lee->lee_parent_fid, sizeof(pfid));
303 fid_be_to_cpu(&pfid, &pfid);
304 fprintf(f, "%s idx=%u parent="DFID" name='",
305 i == 0 ? "linkea:" : " ", i, PFID(&pfid));
306 print_name(f, lee->lee_name, reclen - (int)sizeof(*lee));
309 lee = (struct link_ea_entry *)((char *)lee + reclen);
316 struct dump_attr_pretty {
317 const char *dap_name;
318 int (*dap_print)(FILE *f, char *name, void *value, size_t value_len);
321 .dap_name = "system.posix_acl_access",
322 .dap_print = print_acl,
325 .dap_name = "system.posix_acl_default",
326 .dap_print = print_acl,
329 .dap_name = "trusted.fid",
330 .dap_print = print_fidstr,
333 .dap_name = "trusted.lma",
334 .dap_print = print_lmastr,
337 .dap_name = "trusted.link",
338 .dap_print = print_linkea,
345 static int dump_attr(char *name, char *value, size_t value_len,
346 ext2_ino_t inode_num, void *data)
348 struct dump_attr_pretty *dap;
353 if (EXT2_HAS_INCOMPAT_FEATURE(current_fs->super,
354 EXT4_FEATURE_INCOMPAT_EA_INODE) &&
356 fprintf(out, "inode <%u> ", inode_num);
359 for (dap = dumpers; dap->dap_name != NULL; dap++) {
360 if (strcmp(name, dap->dap_name) == 0) {
361 rc = dap->dap_print(out, name, value, value_len);
365 if (dap->dap_name == NULL || rc)
366 print_xattr(out, name, value, value_len, PRINT_XATTR_STATFMT);
371 void dump_inode_attributes(FILE *out, ext2_ino_t ino)
373 struct ext2_xattr_handle *h;
377 err = ext2fs_xattrs_open(current_fs, ino, &h);
381 err = ext2fs_xattrs_read(h);
385 err = ext2fs_xattrs_count(h, &sz);
389 fprintf(out, "Extended attributes:\n");
390 err = ext2fs_xattrs_iterate(h, dump_attr, out);
395 err = ext2fs_xattrs_close(&h);
398 void do_list_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
399 void *infop EXT2FS_ATTR((unused)))
404 printf("%s: Usage: %s <file>\n", argv[0],
409 if (check_fs_open(argv[0]))
412 ino = string_to_inode(argv[1]);
416 dump_inode_attributes(stdout, ino);
419 void do_get_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
420 void *infop EXT2FS_ATTR((unused)))
423 struct ext2_xattr_handle *h;
429 unsigned int handle_flags = 0;
433 while ((i = getopt(argc, argv, "Cf:rxV")) != -1) {
438 fp = fopen(optarg, "w");
445 handle_flags |= XATTR_HANDLE_FLAG_RAW;
448 print_flags |= PRINT_XATTR_HEX;
451 print_flags |= PRINT_XATTR_RAW|
452 PRINT_XATTR_NOQUOTES;
455 print_flags |= PRINT_XATTR_C;
462 if (optind != argc - 2) {
464 printf("%s: Usage: %s [-f outfile]|[-xVC] [-r] <file> <attr>\n",
470 if (check_fs_open(argv[0]))
473 ino = string_to_inode(argv[optind]);
477 err = ext2fs_xattrs_open(current_fs, ino, &h);
481 err = ext2fs_xattrs_flags(h, &handle_flags, NULL);
485 err = ext2fs_xattrs_read(h);
489 err = ext2fs_xattr_get(h, argv[optind + 1], (void **)&buf, &buflen);
494 fwrite(buf, buflen, 1, fp);
496 if (print_flags & PRINT_XATTR_RAW) {
497 if (print_flags & (PRINT_XATTR_HEX|PRINT_XATTR_C))
498 print_flags &= ~PRINT_XATTR_RAW;
499 print_xattr_string(stdout, buf, buflen, print_flags);
501 print_xattr(stdout, argv[optind + 1],
502 buf, buflen, print_flags);
507 ext2fs_free_mem(&buf);
509 ext2fs_xattrs_close(&h);
511 com_err(argv[0], err, "while getting extended attribute");
517 void do_set_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
518 void *infop EXT2FS_ATTR((unused)))
521 struct ext2_xattr_handle *h;
525 unsigned int handle_flags = 0;
530 while ((i = getopt(argc, argv, "f:r")) != -1) {
535 fp = fopen(optarg, "r");
542 handle_flags |= XATTR_HANDLE_FLAG_RAW;
549 if (!(fp && optind == argc - 2) && !(!fp && optind == argc - 3)) {
551 printf("Usage:\t%s [-r] <file> <attr> <value>\n", argv[0]);
552 printf("\t%s -f <value_file> [-r] <file> <attr>\n", argv[0]);
556 if (check_fs_open(argv[0]))
558 if (check_fs_read_write(argv[0]))
560 if (check_fs_bitmaps(argv[0]))
563 ino = string_to_inode(argv[optind]);
567 err = ext2fs_xattrs_open(current_fs, ino, &h);
571 err = ext2fs_xattrs_flags(h, &handle_flags, NULL);
575 err = ext2fs_xattrs_read(h);
580 err = ext2fs_get_mem(current_fs->blocksize, &buf);
583 buflen = fread(buf, 1, current_fs->blocksize, fp);
585 buf = argv[optind + 2];
586 buflen = parse_c_string(buf);
589 err = ext2fs_xattr_set(h, argv[optind + 1], buf, buflen);
591 ext2fs_xattrs_close(&h);
593 com_err(argv[0], err, "while setting extended attribute");
597 ext2fs_free_mem(&buf);
601 void do_rm_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
602 void *infop EXT2FS_ATTR((unused)))
605 struct ext2_xattr_handle *h;
610 printf("%s: Usage: %s <file> <attrs>...\n", argv[0], argv[0]);
614 if (check_fs_open(argv[0]))
616 if (check_fs_read_write(argv[0]))
618 if (check_fs_bitmaps(argv[0]))
621 ino = string_to_inode(argv[1]);
625 err = ext2fs_xattrs_open(current_fs, ino, &h);
629 err = ext2fs_xattrs_read(h);
633 for (i = 2; i < argc; i++) {
634 err = ext2fs_xattr_remove(h, argv[i]);
639 ext2fs_xattrs_close(&h);
641 com_err(argv[0], err, "while removing extended attribute");
645 * Return non-zero if the string has a minimal number of non-printable
648 static int is_mostly_printable(const char *cp, int len)
656 if (!isprint(*cp++)) {
665 static void safe_print(FILE *f, const char *cp, int len)
678 if ((ch < 32) || (ch == 0x7f)) {
680 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
686 static void dump_xattr_raw_entries(FILE *f, unsigned char *buf,
687 unsigned int start, unsigned int len,
688 unsigned value_start)
690 struct ext2_ext_attr_entry ent;
691 unsigned int off = start;
695 if ((*(__u16 *) (buf + off)) == 0) {
696 fprintf(f, "last entry found at offset %u (%04o)\n",
700 if ((off + sizeof(struct ext2_ext_attr_entry)) >= len) {
701 fprintf(f, "xattr buffer overrun at %u (len = %u)\n",
706 ext2fs_swap_ext_attr_entry(&ent,
707 (struct ext2_ext_attr_entry *) (buf + off));
709 ent = *((struct ext2_ext_attr_entry *) (buf + off));
711 fprintf(f, "offset = %d (%04o), name_len = %u, "
713 off, off, ent.e_name_len, ent.e_name_index);
714 vstart = value_start + ent.e_value_offs;
715 fprintf(f, "value_offset = %d (%04o), value_inum = %u, "
716 "value_size = %u\n", ent.e_value_offs,
717 vstart, ent.e_value_inum, ent.e_value_size);
718 off += sizeof(struct ext2_ext_attr_entry);
719 fprintf(f, "name = ");
720 if ((off + ent.e_name_len) >= len)
721 fprintf(f, "<runs off end>");
723 safe_print(f, (char *)(buf + off), ent.e_name_len);
725 if (ent.e_value_size == 0)
727 fprintf(f, "value = ");
728 if (ent.e_value_inum)
729 fprintf(f, "<ino %u>", ent.e_value_inum);
730 else if (ent.e_value_offs >= len ||
731 (vstart + ent.e_value_size) > len)
732 fprintf(f, "<runs off end>");
733 else if (is_mostly_printable((char *)(buf + vstart),
735 safe_print(f, (char *)(buf + vstart),
738 fprintf(f, "<hexdump>\n");
739 do_byte_hexdump(f, (unsigned char *)(buf + vstart),
745 off += (ent.e_name_len + 3) & ~3;
749 void raw_inode_xattr_dump(FILE *f, unsigned char *buf, unsigned int len)
751 __u32 magic = ext2fs_le32_to_cpu(*((__le32 *) buf));
753 fprintf(f, "magic = %08x, length = %u, value_start =4 \n\n",
755 if (magic == EXT2_EXT_ATTR_MAGIC)
756 dump_xattr_raw_entries(f, buf, 4, len, 4);
759 void block_xattr_dump(FILE *f, unsigned char *buf, unsigned int len)
761 struct ext2_ext_attr_header header;
763 #ifdef WORDS_BIGENDIAN
764 ext2fs_swap_ext_attr_header(&header,
765 (struct ext2_ext_attr_header *) buf);
767 header = *((struct ext2_ext_attr_header *) buf);
769 fprintf(f, "magic = %08x, length = %u\n", header.h_magic, len);
770 if (header.h_magic != EXT2_EXT_ATTR_MAGIC)
772 fprintf(f, "refcount = %u, blocks = %u\n", header.h_refcount,
774 fprintf(f, "hash = %08x, checksum = %08x\n", header.h_hash,
776 fprintf(f, "reserved: %08x %08x %08x\n\n", header.h_reserved[0],
777 header.h_reserved[1], header.h_reserved[2]);
779 dump_xattr_raw_entries(f, buf,
780 sizeof(struct ext2_ext_attr_header), len, 0);