Home | History | Annotate | Download | only in debugfs
      1 /*
      2  * xattrs.c --- Modify extended attributes via debugfs.
      3  *
      4  * Copyright (C) 2014 Oracle.  This file may be redistributed
      5  * under the terms of the GNU Public License.
      6  */
      7 
      8 #include "config.h"
      9 #include <stdio.h>
     10 #ifdef HAVE_GETOPT_H
     11 #include <getopt.h>
     12 #else
     13 extern int optind;
     14 extern char *optarg;
     15 #endif
     16 #include <ctype.h>
     17 #include "support/cstring.h"
     18 
     19 #include "debugfs.h"
     20 
     21 #define PRINT_XATTR_HEX		0x01
     22 #define PRINT_XATTR_RAW		0x02
     23 #define PRINT_XATTR_C		0x04
     24 #define PRINT_XATTR_STATFMT	0x08
     25 #define PRINT_XATTR_NOQUOTES	0x10
     26 
     27 /* Dump extended attributes */
     28 static void print_xattr_hex(FILE *f, const char *str, int len)
     29 {
     30 	int i;
     31 
     32 	for (i = 0; i < len; i++)
     33 		fprintf(f, "%02x ", (unsigned char)str[i]);
     34 }
     35 
     36 /* Dump extended attributes */
     37 static void print_xattr_string(FILE *f, const char *str, int len, int flags)
     38 {
     39 	int printable = 0;
     40 	int i;
     41 
     42 	if (flags & PRINT_XATTR_RAW) {
     43 		fwrite(str, len, 1, f);
     44 		return;
     45 	}
     46 
     47 	if ((flags & PRINT_XATTR_C) == 0) {
     48 		/* check: is string "printable enough?" */
     49 		for (i = 0; i < len; i++)
     50 			if (isprint(str[i]))
     51 				printable++;
     52 
     53 		if (printable <= len*7/8)
     54 			flags |= PRINT_XATTR_HEX;
     55 	}
     56 
     57 	if (flags & PRINT_XATTR_HEX) {
     58 		print_xattr_hex(f, str, len);
     59 	} else {
     60 		if ((flags & PRINT_XATTR_NOQUOTES) == 0)
     61 			fputc('\"', f);
     62 		print_c_string(f, str, len);
     63 		if ((flags & PRINT_XATTR_NOQUOTES) == 0)
     64 			fputc('\"', f);
     65 	}
     66 }
     67 
     68 static void print_xattr(FILE *f, char *name, char *value, size_t value_len,
     69 			int print_flags)
     70 {
     71 	print_xattr_string(f, name, strlen(name), PRINT_XATTR_NOQUOTES);
     72 	fprintf(f, " (%zu)", value_len);
     73 	if ((print_flags & PRINT_XATTR_STATFMT) &&
     74 	    (strcmp(name, "system.data") == 0))
     75 		value_len = 0;
     76 	if (value_len != 0 &&
     77 	    (!(print_flags & PRINT_XATTR_STATFMT) || (value_len < 40))) {
     78 		fprintf(f, " = ");
     79 		print_xattr_string(f, value, value_len, print_flags);
     80 	}
     81 	fputc('\n', f);
     82 }
     83 
     84 static int dump_attr(char *name, char *value, size_t value_len, void *data)
     85 {
     86 	FILE *out = data;
     87 
     88 	fprintf(out, "  ");
     89 	print_xattr(out, name, value, value_len, PRINT_XATTR_STATFMT);
     90 	return 0;
     91 }
     92 
     93 void dump_inode_attributes(FILE *out, ext2_ino_t ino)
     94 {
     95 	struct ext2_xattr_handle *h;
     96 	size_t sz;
     97 	errcode_t err;
     98 
     99 	err = ext2fs_xattrs_open(current_fs, ino, &h);
    100 	if (err)
    101 		return;
    102 
    103 	err = ext2fs_xattrs_read(h);
    104 	if (err)
    105 		goto out;
    106 
    107 	err = ext2fs_xattrs_count(h, &sz);
    108 	if (err || sz == 0)
    109 		goto out;
    110 
    111 	fprintf(out, "Extended attributes:\n");
    112 	err = ext2fs_xattrs_iterate(h, dump_attr, out);
    113 	if (err)
    114 		goto out;
    115 
    116 out:
    117 	err = ext2fs_xattrs_close(&h);
    118 }
    119 
    120 void do_list_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
    121 		   void *infop EXT2FS_ATTR((unused)))
    122 {
    123 	ext2_ino_t ino;
    124 
    125 	if (argc != 2) {
    126 		printf("%s: Usage: %s <file>\n", argv[0],
    127 		       argv[0]);
    128 		return;
    129 	}
    130 
    131 	if (check_fs_open(argv[0]))
    132 		return;
    133 
    134 	ino = string_to_inode(argv[1]);
    135 	if (!ino)
    136 		return;
    137 
    138 	dump_inode_attributes(stdout, ino);
    139 }
    140 
    141 void do_get_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
    142 		  void *infop EXT2FS_ATTR((unused)))
    143 {
    144 	ext2_ino_t ino;
    145 	struct ext2_xattr_handle *h;
    146 	FILE *fp = NULL;
    147 	char *buf = NULL;
    148 	size_t buflen;
    149 	int i;
    150 	int print_flags = 0;
    151 	unsigned int handle_flags = 0;
    152 	errcode_t err;
    153 
    154 	reset_getopt();
    155 	while ((i = getopt(argc, argv, "Cf:rxV")) != -1) {
    156 		switch (i) {
    157 		case 'f':
    158 			if (fp)
    159 				fclose(fp);
    160 			fp = fopen(optarg, "w");
    161 			if (fp == NULL) {
    162 				perror(optarg);
    163 				return;
    164 			}
    165 			break;
    166 		case 'r':
    167 			handle_flags |= XATTR_HANDLE_FLAG_RAW;
    168 			break;
    169 		case 'x':
    170 			print_flags |= PRINT_XATTR_HEX;
    171 			break;
    172 		case 'V':
    173 			print_flags |= PRINT_XATTR_RAW|
    174 				PRINT_XATTR_NOQUOTES;
    175 			break;
    176 		case 'C':
    177 			print_flags |= PRINT_XATTR_C;
    178 			break;
    179 		default:
    180 			goto usage;
    181 		}
    182 	}
    183 
    184 	if (optind != argc - 2) {
    185 	usage:
    186 		printf("%s: Usage: %s [-f outfile]|[-xVC] [-r] <file> <attr>\n",
    187 			       argv[0], argv[0]);
    188 
    189 		goto out2;
    190 	}
    191 
    192 	if (check_fs_open(argv[0]))
    193 		goto out2;
    194 
    195 	ino = string_to_inode(argv[optind]);
    196 	if (!ino)
    197 		goto out2;
    198 
    199 	err = ext2fs_xattrs_open(current_fs, ino, &h);
    200 	if (err)
    201 		goto out2;
    202 
    203 	err = ext2fs_xattrs_flags(h, &handle_flags, NULL);
    204 	if (err)
    205 		goto out;
    206 
    207 	err = ext2fs_xattrs_read(h);
    208 	if (err)
    209 		goto out;
    210 
    211 	err = ext2fs_xattr_get(h, argv[optind + 1], (void **)&buf, &buflen);
    212 	if (err)
    213 		goto out;
    214 
    215 	if (fp) {
    216 		fwrite(buf, buflen, 1, fp);
    217 	} else {
    218 		if (print_flags & PRINT_XATTR_RAW) {
    219 			if (print_flags & (PRINT_XATTR_HEX|PRINT_XATTR_C))
    220 				print_flags &= ~PRINT_XATTR_RAW;
    221 			print_xattr_string(stdout, buf, buflen, print_flags);
    222 		} else {
    223 			print_xattr(stdout, argv[optind + 1],
    224 				    buf, buflen, print_flags);
    225 		}
    226 		printf("\n");
    227 	}
    228 
    229 	ext2fs_free_mem(&buf);
    230 out:
    231 	ext2fs_xattrs_close(&h);
    232 	if (err)
    233 		com_err(argv[0], err, "while getting extended attribute");
    234 out2:
    235 	if (fp)
    236 		fclose(fp);
    237 }
    238 
    239 void do_set_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
    240 		  void *infop EXT2FS_ATTR((unused)))
    241 {
    242 	ext2_ino_t ino;
    243 	struct ext2_xattr_handle *h;
    244 	FILE *fp = NULL;
    245 	char *buf = NULL;
    246 	size_t buflen;
    247 	unsigned int handle_flags = 0;
    248 	int i;
    249 	errcode_t err;
    250 
    251 	reset_getopt();
    252 	while ((i = getopt(argc, argv, "f:r")) != -1) {
    253 		switch (i) {
    254 		case 'f':
    255 			if (fp)
    256 				fclose(fp);
    257 			fp = fopen(optarg, "r");
    258 			if (fp == NULL) {
    259 				perror(optarg);
    260 				return;
    261 			}
    262 			break;
    263 		case 'r':
    264 			handle_flags |= XATTR_HANDLE_FLAG_RAW;
    265 			break;
    266 		default:
    267 			goto print_usage;
    268 		}
    269 	}
    270 
    271 	if (!(fp && optind == argc - 2) && !(!fp && optind == argc - 3)) {
    272 	print_usage:
    273 		printf("Usage:\t%s [-r] <file> <attr> <value>\n", argv[0]);
    274 		printf("\t%s -f <value_file> [-r] <file> <attr>\n", argv[0]);
    275 		goto out2;
    276 	}
    277 
    278 	if (check_fs_open(argv[0]))
    279 		goto out2;
    280 	if (check_fs_read_write(argv[0]))
    281 		goto out2;
    282 	if (check_fs_bitmaps(argv[0]))
    283 		goto out2;
    284 
    285 	ino = string_to_inode(argv[optind]);
    286 	if (!ino)
    287 		goto out2;
    288 
    289 	err = ext2fs_xattrs_open(current_fs, ino, &h);
    290 	if (err)
    291 		goto out2;
    292 
    293 	err = ext2fs_xattrs_flags(h, &handle_flags, NULL);
    294 	if (err)
    295 		goto out;
    296 
    297 	err = ext2fs_xattrs_read(h);
    298 	if (err)
    299 		goto out;
    300 
    301 	if (fp) {
    302 		err = ext2fs_get_mem(current_fs->blocksize, &buf);
    303 		if (err)
    304 			goto out;
    305 		buflen = fread(buf, 1, current_fs->blocksize, fp);
    306 	} else {
    307 		buf = argv[optind + 2];
    308 		buflen = parse_c_string(buf);
    309 	}
    310 
    311 	err = ext2fs_xattr_set(h, argv[optind + 1], buf, buflen);
    312 out:
    313 	ext2fs_xattrs_close(&h);
    314 	if (err)
    315 		com_err(argv[0], err, "while setting extended attribute");
    316 out2:
    317 	if (fp) {
    318 		fclose(fp);
    319 		ext2fs_free_mem(&buf);
    320 	}
    321 }
    322 
    323 void do_rm_xattr(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)),
    324 		 void *infop EXT2FS_ATTR((unused)))
    325 {
    326 	ext2_ino_t ino;
    327 	struct ext2_xattr_handle *h;
    328 	int i;
    329 	errcode_t err;
    330 
    331 	if (argc < 3) {
    332 		printf("%s: Usage: %s <file> <attrs>...\n", argv[0], argv[0]);
    333 		return;
    334 	}
    335 
    336 	if (check_fs_open(argv[0]))
    337 		return;
    338 	if (check_fs_read_write(argv[0]))
    339 		return;
    340 	if (check_fs_bitmaps(argv[0]))
    341 		return;
    342 
    343 	ino = string_to_inode(argv[1]);
    344 	if (!ino)
    345 		return;
    346 
    347 	err = ext2fs_xattrs_open(current_fs, ino, &h);
    348 	if (err)
    349 		return;
    350 
    351 	err = ext2fs_xattrs_read(h);
    352 	if (err)
    353 		goto out;
    354 
    355 	for (i = 2; i < argc; i++) {
    356 		err = ext2fs_xattr_remove(h, argv[i]);
    357 		if (err)
    358 			goto out;
    359 	}
    360 out:
    361 	ext2fs_xattrs_close(&h);
    362 	if (err)
    363 		com_err(argv[0], err, "while removing extended attribute");
    364 }
    365 
    366 /*
    367  * Return non-zero if the string has a minimal number of non-printable
    368  * characters.
    369  */
    370 static int is_mostly_printable(const char *cp, int len)
    371 {
    372 	int	np = 0;
    373 
    374 	if (len < 0)
    375 		len = strlen(cp);
    376 
    377 	while (len--) {
    378 		if (!isprint(*cp++)) {
    379 			np++;
    380 			if (np > 3)
    381 				return 0;
    382 		}
    383 	}
    384 	return 1;
    385 }
    386 
    387 static void safe_print(FILE *f, const char *cp, int len)
    388 {
    389 	unsigned char	ch;
    390 
    391 	if (len < 0)
    392 		len = strlen(cp);
    393 
    394 	while (len--) {
    395 		ch = *cp++;
    396 		if (ch > 128) {
    397 			fputs("M-", f);
    398 			ch -= 128;
    399 		}
    400 		if ((ch < 32) || (ch == 0x7f)) {
    401 			fputc('^', f);
    402 			ch ^= 0x40; /* ^@, ^A, ^B; ^? for DEL */
    403 		}
    404 		fputc(ch, f);
    405 	}
    406 }
    407 
    408 static void dump_xattr_raw_entries(FILE *f, unsigned char *buf,
    409 				   unsigned int start, unsigned int len,
    410 				   unsigned value_start)
    411 {
    412 	struct ext2_ext_attr_entry ent;
    413 	unsigned int off = start;
    414 	unsigned int vstart;
    415 
    416 	while (off < len) {
    417 		if ((*(__u16 *) (buf + off)) == 0) {
    418 			fprintf(f, "last entry found at offset %u (%04o)\n",
    419 				off, off);
    420 			break;
    421 		}
    422 		if ((off + sizeof(struct ext2_ext_attr_entry)) >= len) {
    423 			fprintf(f, "xattr buffer overrun at %u (len = %u)\n",
    424 				off, len);
    425 			break;
    426 		}
    427 #if WORDS_BIGENDIAN
    428 		ext2fs_swap_ext_attr_entry(&ent,
    429 			(struct ext2_ext_attr_entry *) (buf + off));
    430 #else
    431 		ent = *((struct ext2_ext_attr_entry *) (buf + off));
    432 #endif
    433 		fprintf(f, "offset = %d (%04o), name_len = %u, "
    434 			"name_index = %u\n",
    435 			off, off, ent.e_name_len, ent.e_name_index);
    436 		vstart = value_start + ent.e_value_offs;
    437 		fprintf(f, "value_offset = %d (%04o), value_inum = %u, "
    438 			"value_size = %u\n", ent.e_value_offs,
    439 			vstart, ent.e_value_inum, ent.e_value_size);
    440 		off += sizeof(struct ext2_ext_attr_entry);
    441 		fprintf(f, "name = ");
    442 		if ((off + ent.e_name_len) >= len)
    443 			fprintf(f, "<runs off end>");
    444 		else
    445 			safe_print(f, (char *)(buf + off), ent.e_name_len);
    446 		fputc('\n', f);
    447 		if (ent.e_value_size == 0)
    448 			goto skip_value;
    449 		fprintf(f, "value = ");
    450 		if (ent.e_value_inum)
    451 			fprintf(f, "<ino %u>", ent.e_value_inum);
    452 		else if (ent.e_value_offs >= len ||
    453 			 (vstart + ent.e_value_size) > len)
    454 			fprintf(f, "<runs off end>");
    455 		if (is_mostly_printable((char *)(buf + vstart),
    456 					ent.e_value_size))
    457 			safe_print(f, (char *)(buf + vstart),
    458 				   ent.e_value_size);
    459 		else {
    460 			fprintf(f, "<hexdump>\n");
    461 			do_byte_hexdump(f, (unsigned char *)(buf + vstart),
    462 					ent.e_value_size);
    463 		}
    464 		fputc('\n', f);
    465 	skip_value:
    466 		fputc('\n', f);
    467 		off += (ent.e_name_len + 3) & ~3;
    468 	}
    469 }
    470 
    471 void raw_inode_xattr_dump(FILE *f, unsigned char *buf, unsigned int len)
    472 {
    473 	__u32 magic = ext2fs_le32_to_cpu(*((__le32 *) buf));
    474 
    475 	fprintf(f, "magic = %08x, length = %u, value_start =4 \n\n",
    476 		magic, len);
    477 	if (magic == EXT2_EXT_ATTR_MAGIC)
    478 		dump_xattr_raw_entries(f, buf, 4, len, 4);
    479 }
    480 
    481 void block_xattr_dump(FILE *f, unsigned char *buf, unsigned int len)
    482 {
    483 	struct ext2_ext_attr_header header;
    484 
    485 #ifdef WORDS_BIGENDIAN
    486 	ext2fs_swap_ext_attr_header(&header,
    487 				    (struct ext2_ext_attr_header *) buf);
    488 #else
    489 	header = *((struct ext2_ext_attr_header *) buf);
    490 #endif
    491 	fprintf(f, "magic = %08x, length = %u\n", header.h_magic, len);
    492 	if (header.h_magic != EXT2_EXT_ATTR_MAGIC)
    493 		return;
    494 	fprintf(f, "refcount = %u, blocks = %u\n", header.h_refcount,
    495 		header.h_blocks);
    496 	fprintf(f, "hash = %08x, checksum = %08x\n", header.h_hash,
    497 		header.h_checksum);
    498 	fprintf(f, "reserved: %08x %08x %08x\n\n", header.h_reserved[0],
    499 		header.h_reserved[1], header.h_reserved[2]);
    500 
    501 	dump_xattr_raw_entries(f, buf,
    502 			       sizeof(struct ext2_ext_attr_header), len, 0);
    503 }
    504