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, void *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, void *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, void *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 int print_linkea(FILE *f, void *name, void *value, size_t value_len)
252 struct link_ea_header *leh = value;
253 struct link_ea_entry *lee;
256 if (value_len < sizeof(*leh) ||
257 value_len < ext2fs_le64_to_cpu(leh->leh_len)) {
258 fprintf(stderr, "%s: error: xattr '%s' too small (%zu bytes)\n",
259 debug_prog_name, name, value_len);
263 if (ext2fs_le32_to_cpu(leh->leh_magic) != LINK_EA_MAGIC) {
264 fprintf(stderr, "%s: error: xattr '%s' bad magic '%#x'\n",
265 debug_prog_name, name,
266 ext2fs_le32_to_cpu(leh->leh_magic));
270 lee = leh->leh_entry;
271 value_len -= sizeof(*leh);
273 for (i = 0; i < ext2fs_le32_to_cpu(leh->leh_reccount) &&
274 value_len > 2; i++) {
275 int reclen = lee->lee_reclen[0] << 8 | lee->lee_reclen[1];
278 if (value_len < sizeof(*lee) || value_len < reclen) {
280 "%s: error: xattr '%s' entry %d too small "
282 debug_prog_name, name, i, value_len);
286 memcpy(&pfid, &lee->lee_parent_fid, sizeof(pfid));
287 fid_be_to_cpu(&pfid, &pfid);
288 fprintf(f, "%s idx=%u parent="DFID" name='%.*s'\n",
289 i == 0 ? "linkea:" : " ", i, PFID(&pfid),
290 reclen - (int)sizeof(*lee), lee->lee_name);
292 lee = (struct link_ea_entry *)((char *)lee + reclen);
299 struct dump_attr_pretty {
300 const char *dap_name;
301 int (*dap_print)(FILE *f, void *name, void *value, size_t value_len);
304 .dap_name = "system.posix_acl_access",
305 .dap_print = print_acl,
308 .dap_name = "system.posix_acl_default",
309 .dap_print = print_acl,
312 .dap_name = "trusted.fid",
313 .dap_print = print_fidstr,
316 .dap_name = "trusted.lma",
317 .dap_print = print_lmastr,
320 .dap_name = "trusted.link",
321 .dap_print = print_linkea,
328 static int dump_attr(char *name, char *value, size_t value_len,
329 ext2_ino_t inode_num, void *data)
331 struct dump_attr_pretty *dap;
336 if (EXT2_HAS_INCOMPAT_FEATURE(current_fs->super,
337 EXT4_FEATURE_INCOMPAT_EA_INODE) &&
339 fprintf(out, "inode <%u> ", inode_num);
342 for (dap = dumpers; dap->dap_name != NULL; dap++) {
343 if (strcmp(name, dap->dap_name) == 0) {
344 rc = dap->dap_print(out, name, value, value_len);
348 if (dap->dap_name == NULL || rc)
349 print_xattr(out, name, value, value_len, PRINT_XATTR_STATFMT);
354 void dump_inode_attributes(FILE *out, ext2_ino_t ino)
356 struct ext2_xattr_handle *h;
360 err = ext2fs_xattrs_open(current_fs, ino, &h);
364 err = ext2fs_xattrs_read(h);
368 err = ext2fs_xattrs_count(h, &sz);
372 fprintf(out, "Extended attributes:\n");
373 err = ext2fs_xattrs_iterate(h, dump_attr, out);
378 err = ext2fs_xattrs_close(&h);
381 void do_list_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
382 void *infop EXT2FS_ATTR((unused)))
387 printf("%s: Usage: %s <file>\n", argv[0],
392 if (check_fs_open(argv[0]))
395 ino = string_to_inode(argv[1]);
399 dump_inode_attributes(stdout, ino);
402 void do_get_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
403 void *infop EXT2FS_ATTR((unused)))
406 struct ext2_xattr_handle *h;
412 unsigned int handle_flags = 0;
416 while ((i = getopt(argc, argv, "Cf:rxV")) != -1) {
421 fp = fopen(optarg, "w");
428 handle_flags |= XATTR_HANDLE_FLAG_RAW;
431 print_flags |= PRINT_XATTR_HEX;
434 print_flags |= PRINT_XATTR_RAW|
435 PRINT_XATTR_NOQUOTES;
438 print_flags |= PRINT_XATTR_C;
445 if (optind != argc - 2) {
447 printf("%s: Usage: %s [-f outfile]|[-xVC] [-r] <file> <attr>\n",
453 if (check_fs_open(argv[0]))
456 ino = string_to_inode(argv[optind]);
460 err = ext2fs_xattrs_open(current_fs, ino, &h);
464 err = ext2fs_xattrs_flags(h, &handle_flags, NULL);
468 err = ext2fs_xattrs_read(h);
472 err = ext2fs_xattr_get(h, argv[optind + 1], (void **)&buf, &buflen);
477 fwrite(buf, buflen, 1, fp);
479 if (print_flags & PRINT_XATTR_RAW) {
480 if (print_flags & (PRINT_XATTR_HEX|PRINT_XATTR_C))
481 print_flags &= ~PRINT_XATTR_RAW;
482 print_xattr_string(stdout, buf, buflen, print_flags);
484 print_xattr(stdout, argv[optind + 1],
485 buf, buflen, print_flags);
490 ext2fs_free_mem(&buf);
492 ext2fs_xattrs_close(&h);
494 com_err(argv[0], err, "while getting extended attribute");
500 void do_set_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
501 void *infop EXT2FS_ATTR((unused)))
504 struct ext2_xattr_handle *h;
508 unsigned int handle_flags = 0;
513 while ((i = getopt(argc, argv, "f:r")) != -1) {
518 fp = fopen(optarg, "r");
525 handle_flags |= XATTR_HANDLE_FLAG_RAW;
532 if (!(fp && optind == argc - 2) && !(!fp && optind == argc - 3)) {
534 printf("Usage:\t%s [-r] <file> <attr> <value>\n", argv[0]);
535 printf("\t%s -f <value_file> [-r] <file> <attr>\n", argv[0]);
539 if (check_fs_open(argv[0]))
541 if (check_fs_read_write(argv[0]))
543 if (check_fs_bitmaps(argv[0]))
546 ino = string_to_inode(argv[optind]);
550 err = ext2fs_xattrs_open(current_fs, ino, &h);
554 err = ext2fs_xattrs_flags(h, &handle_flags, NULL);
558 err = ext2fs_xattrs_read(h);
563 err = ext2fs_get_mem(current_fs->blocksize, &buf);
566 buflen = fread(buf, 1, current_fs->blocksize, fp);
568 buf = argv[optind + 2];
569 buflen = parse_c_string(buf);
572 err = ext2fs_xattr_set(h, argv[optind + 1], buf, buflen);
574 ext2fs_xattrs_close(&h);
576 com_err(argv[0], err, "while setting extended attribute");
580 ext2fs_free_mem(&buf);
584 void do_rm_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
585 void *infop EXT2FS_ATTR((unused)))
588 struct ext2_xattr_handle *h;
593 printf("%s: Usage: %s <file> <attrs>...\n", argv[0], argv[0]);
597 if (check_fs_open(argv[0]))
599 if (check_fs_read_write(argv[0]))
601 if (check_fs_bitmaps(argv[0]))
604 ino = string_to_inode(argv[1]);
608 err = ext2fs_xattrs_open(current_fs, ino, &h);
612 err = ext2fs_xattrs_read(h);
616 for (i = 2; i < argc; i++) {
617 err = ext2fs_xattr_remove(h, argv[i]);
622 ext2fs_xattrs_close(&h);
624 com_err(argv[0], err, "while removing extended attribute");
628 * Return non-zero if the string has a minimal number of non-printable
631 static int is_mostly_printable(const char *cp, int len)
639 if (!isprint(*cp++)) {
648 static void safe_print(FILE *f, const char *cp, int len)
661 if ((ch < 32) || (ch == 0x7f)) {
663 ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
669 static void dump_xattr_raw_entries(FILE *f, unsigned char *buf,
670 unsigned int start, unsigned int len,
671 unsigned value_start)
673 struct ext2_ext_attr_entry ent;
674 unsigned int off = start;
678 if ((*(__u16 *) (buf + off)) == 0) {
679 fprintf(f, "last entry found at offset %u (%04o)\n",
683 if ((off + sizeof(struct ext2_ext_attr_entry)) >= len) {
684 fprintf(f, "xattr buffer overrun at %u (len = %u)\n",
689 ext2fs_swap_ext_attr_entry(&ent,
690 (struct ext2_ext_attr_entry *) (buf + off));
692 ent = *((struct ext2_ext_attr_entry *) (buf + off));
694 fprintf(f, "offset = %d (%04o), name_len = %u, "
696 off, off, ent.e_name_len, ent.e_name_index);
697 vstart = value_start + ent.e_value_offs;
698 fprintf(f, "value_offset = %d (%04o), value_inum = %u, "
699 "value_size = %u\n", ent.e_value_offs,
700 vstart, ent.e_value_inum, ent.e_value_size);
701 off += sizeof(struct ext2_ext_attr_entry);
702 fprintf(f, "name = ");
703 if ((off + ent.e_name_len) >= len)
704 fprintf(f, "<runs off end>");
706 safe_print(f, (char *)(buf + off), ent.e_name_len);
708 if (ent.e_value_size == 0)
710 fprintf(f, "value = ");
711 if (ent.e_value_inum)
712 fprintf(f, "<ino %u>", ent.e_value_inum);
713 else if (ent.e_value_offs >= len ||
714 (vstart + ent.e_value_size) > len)
715 fprintf(f, "<runs off end>");
716 else if (is_mostly_printable((char *)(buf + vstart),
718 safe_print(f, (char *)(buf + vstart),
721 fprintf(f, "<hexdump>\n");
722 do_byte_hexdump(f, (unsigned char *)(buf + vstart),
728 off += (ent.e_name_len + 3) & ~3;
732 void raw_inode_xattr_dump(FILE *f, unsigned char *buf, unsigned int len)
734 __u32 magic = ext2fs_le32_to_cpu(*((__le32 *) buf));
736 fprintf(f, "magic = %08x, length = %u, value_start =4 \n\n",
738 if (magic == EXT2_EXT_ATTR_MAGIC)
739 dump_xattr_raw_entries(f, buf, 4, len, 4);
742 void block_xattr_dump(FILE *f, unsigned char *buf, unsigned int len)
744 struct ext2_ext_attr_header header;
746 #ifdef WORDS_BIGENDIAN
747 ext2fs_swap_ext_attr_header(&header,
748 (struct ext2_ext_attr_header *) buf);
750 header = *((struct ext2_ext_attr_header *) buf);
752 fprintf(f, "magic = %08x, length = %u\n", header.h_magic, len);
753 if (header.h_magic != EXT2_EXT_ATTR_MAGIC)
755 fprintf(f, "refcount = %u, blocks = %u\n", header.h_refcount,
757 fprintf(f, "hash = %08x, checksum = %08x\n", header.h_hash,
759 fprintf(f, "reserved: %08x %08x %08x\n\n", header.h_reserved[0],
760 header.h_reserved[1], header.h_reserved[2]);
762 dump_xattr_raw_entries(f, buf,
763 sizeof(struct ext2_ext_attr_header), len, 0);