Home | History | Annotate | Download | only in debugfs
      1 /*
      2  * extent_inode.c --- direct extent tree manipulation
      3  *
      4  * Copyright (C) 2012 Theodore Ts'o.  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 #include <unistd.h>
     11 #include <stdlib.h>
     12 #include <ctype.h>
     13 #include <string.h>
     14 #include <time.h>
     15 #ifdef HAVE_ERRNO_H
     16 #include <errno.h>
     17 #endif
     18 #include <sys/types.h>
     19 #ifdef HAVE_GETOPT_H
     20 #include <getopt.h>
     21 #else
     22 extern int optind;
     23 extern char *optarg;
     24 #endif
     25 
     26 #include "debugfs.h"
     27 
     28 static ext2_ino_t	current_ino;
     29 static ext2_extent_handle_t current_handle;
     30 
     31 static void dbg_print_extent(char *desc, struct ext2fs_extent *extent)
     32 {
     33 	if (desc)
     34 		printf("%s: ", desc);
     35 	printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
     36 	       extent->e_lblk, extent->e_lblk + extent->e_len - 1,
     37 	       extent->e_len, extent->e_pblk);
     38 	if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
     39 		fputs("LEAF ", stdout);
     40 	if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
     41 		fputs("UNINIT ", stdout);
     42 	if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
     43 		fputs("2ND_VISIT ", stdout);
     44 	if (!extent->e_flags)
     45 		fputs("(none)", stdout);
     46 	fputc('\n', stdout);
     47 
     48 }
     49 
     50 static int common_extent_args_process(int argc, char *argv[], int min_argc,
     51 				      int max_argc, const char *cmd,
     52 				      const char *usage, int flags)
     53 {
     54 	if (common_args_process(argc, argv, min_argc, max_argc, cmd,
     55 				usage, flags))
     56 		return 1;
     57 
     58 	if (!current_handle) {
     59 		com_err(cmd, 0, "Extent handle not open");
     60 		return 1;
     61 	}
     62 	return 0;
     63 }
     64 
     65 static char *orig_prompt, *extent_prompt;
     66 
     67 void do_extent_open(int argc, char *argv[])
     68 {
     69 	ext2_ino_t	inode;
     70 	int		ret;
     71 	errcode_t	retval;
     72 	char		*cp;
     73 
     74 	if (check_fs_open(argv[0]))
     75 		return;
     76 
     77 	if (argc == 1) {
     78 		if (current_ino)
     79 			printf("Current inode is %d\n", current_ino);
     80 		else
     81 			printf("No current inode\n");
     82 		return;
     83 	}
     84 
     85 	if (common_inode_args_process(argc, argv, &inode, 0))
     86 		return;
     87 
     88 	current_ino = 0;
     89 
     90 	retval = ext2fs_extent_open(current_fs, inode, &current_handle);
     91 	if (retval) {
     92 		com_err(argv[1], retval, "while opening extent handle");
     93 		return;
     94 	}
     95 
     96 	current_ino = inode;
     97 
     98 	orig_prompt = ss_get_prompt(sci_idx);
     99 	extent_prompt = malloc(strlen(orig_prompt) + 32);
    100 	if (extent_prompt == NULL) {
    101 		com_err(argv[1], retval, "out of memory");
    102 		return;
    103 	}
    104 
    105 	strcpy(extent_prompt, orig_prompt);
    106 	cp = strchr(extent_prompt, ':');
    107 	if (cp)
    108 		*cp = 0;
    109 	sprintf(extent_prompt + strlen(extent_prompt), " (extent ino %d): ",
    110 		current_ino);
    111 	ss_add_request_table(sci_idx, &extent_cmds, 1, &ret);
    112 	ss_set_prompt(sci_idx, extent_prompt);
    113 	return;
    114 }
    115 
    116 void do_extent_close(int argc, char *argv[])
    117 {
    118 	int ret;
    119 
    120 	if (common_args_process(argc, argv, 1, 1,
    121 				"extent_close", "", 0))
    122 		return;
    123 
    124 	if (!current_handle) {
    125 		com_err(argv[0], 0, "Extent handle not open");
    126 		return;
    127 	}
    128 
    129 	ext2fs_extent_free(current_handle);
    130 	current_handle = NULL;
    131 	current_ino = 0;
    132 	ss_delete_request_table(sci_idx, &extent_cmds, &ret);
    133 	ss_set_prompt(sci_idx, orig_prompt);
    134 	free(extent_prompt);
    135 	extent_prompt = NULL;
    136 }
    137 
    138 static void generic_goto_node(const char *my_name, int argc,
    139 			      char **argv, int op)
    140 {
    141 	struct ext2fs_extent	extent;
    142 	errcode_t		retval;
    143 
    144 	if (my_name && common_args_process(argc, argv, 1, 1,
    145 					   my_name, "", 0))
    146 		return;
    147 
    148 	if (!current_handle) {
    149 		com_err(argv[0], 0, "Extent handle not open");
    150 		return;
    151 	}
    152 
    153 	retval = ext2fs_extent_get(current_handle, op, &extent);
    154 	if (retval) {
    155 		com_err(argv[0], retval, 0);
    156 		return;
    157 	}
    158 	dbg_print_extent(0, &extent);
    159 }
    160 
    161 void do_current_node(int argc, char *argv[])
    162 {
    163 	generic_goto_node("current_node", argc, argv, EXT2_EXTENT_CURRENT);
    164 }
    165 
    166 void do_root_node(int argc, char *argv[])
    167 {
    168 	generic_goto_node("root_node", argc, argv, EXT2_EXTENT_ROOT);
    169 }
    170 
    171 void do_last_leaf(int argc, char *argv[])
    172 {
    173 	generic_goto_node("last_leaf", argc, argv, EXT2_EXTENT_LAST_LEAF);
    174 }
    175 
    176 void do_first_sib(int argc, char *argv[])
    177 {
    178 	generic_goto_node("first_sib", argc, argv, EXT2_EXTENT_FIRST_SIB);
    179 }
    180 
    181 void do_last_sib(int argc, char *argv[])
    182 {
    183 	generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_LAST_SIB);
    184 }
    185 
    186 void do_next_sib(int argc, char *argv[])
    187 {
    188 	generic_goto_node("next_sib", argc, argv, EXT2_EXTENT_NEXT_SIB);
    189 }
    190 
    191 void do_prev_sib(int argc, char *argv[])
    192 {
    193 	generic_goto_node("prev_sib", argc, argv, EXT2_EXTENT_PREV_SIB);
    194 }
    195 
    196 void do_next_leaf(int argc, char *argv[])
    197 {
    198 	generic_goto_node("next_leaf", argc, argv, EXT2_EXTENT_NEXT_LEAF);
    199 }
    200 
    201 void do_prev_leaf(int argc, char *argv[])
    202 {
    203 	generic_goto_node("prev_leaf", argc, argv, EXT2_EXTENT_PREV_LEAF);
    204 }
    205 
    206 void do_next(int argc, char *argv[])
    207 {
    208 	generic_goto_node("next", argc, argv, EXT2_EXTENT_NEXT);
    209 }
    210 
    211 void do_prev(int argc, char *argv[])
    212 {
    213 	generic_goto_node("prev", argc, argv, EXT2_EXTENT_PREV);
    214 }
    215 
    216 void do_up(int argc, char *argv[])
    217 {
    218 	generic_goto_node("up", argc, argv, EXT2_EXTENT_UP);
    219 }
    220 
    221 void do_down(int argc, char *argv[])
    222 {
    223 	generic_goto_node("down", argc, argv, EXT2_EXTENT_DOWN);
    224 }
    225 
    226 void do_delete_node(int argc, char *argv[])
    227 {
    228 	struct ext2fs_extent extent;
    229 	errcode_t	retval;
    230 
    231 	if (common_extent_args_process(argc, argv, 1, 1, "delete_node",
    232 				       "", CHECK_FS_RW | CHECK_FS_BITMAPS))
    233 		return;
    234 
    235 	retval = ext2fs_extent_delete(current_handle, 0);
    236 	if (retval) {
    237 		com_err(argv[0], retval, 0);
    238 		return;
    239 	}
    240 
    241 	retval = ext2fs_extent_get(current_handle, EXT2_EXTENT_CURRENT,
    242 				   &extent);
    243 	if (retval)
    244 		return;
    245 	dbg_print_extent(0, &extent);
    246 }
    247 
    248 void do_replace_node(int argc, char *argv[])
    249 {
    250 	const char	*usage = "[--uninit] <lblk> <len> <pblk>";
    251 	errcode_t	retval;
    252 	struct ext2fs_extent extent;
    253 	int err;
    254 
    255 	if (common_extent_args_process(argc, argv, 3, 5, "replace_node",
    256 				       usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
    257 		return;
    258 
    259 	extent.e_flags = 0;
    260 
    261 	if (!strcmp(argv[1], "--uninit")) {
    262 		argc--;
    263 		argv++;
    264 		extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
    265 	}
    266 
    267 	if (argc != 4) {
    268 		fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
    269 		return;
    270 	}
    271 
    272 	err = strtoblk(argv[0], argv[1], "logical block", &extent.e_lblk);
    273 	if (err)
    274 		return;
    275 
    276 	extent.e_len = parse_ulong(argv[2], argv[0], "length", &err);
    277 	if (err)
    278 		return;
    279 
    280 	err = strtoblk(argv[0], argv[3], "physical block", &extent.e_pblk);
    281 	if (err)
    282 		return;
    283 
    284 	retval = ext2fs_extent_replace(current_handle, 0, &extent);
    285 	if (retval) {
    286 		com_err(argv[0], retval, 0);
    287 		return;
    288 	}
    289 	generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
    290 }
    291 
    292 void do_split_node(int argc, char *argv[])
    293 {
    294 	errcode_t	retval;
    295 
    296 	if (common_extent_args_process(argc, argv, 1, 1, "split_node",
    297 				       "", CHECK_FS_RW | CHECK_FS_BITMAPS))
    298 		return;
    299 
    300 	retval = ext2fs_extent_node_split(current_handle);
    301 	if (retval) {
    302 		com_err(argv[0], retval, 0);
    303 		return;
    304 	}
    305 	generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
    306 }
    307 
    308 void do_insert_node(int argc, char *argv[])
    309 {
    310 	const char	*usage = "[--after] [--uninit] <lblk> <len> <pblk>";
    311 	errcode_t	retval;
    312 	struct ext2fs_extent extent;
    313 	char *cmd;
    314 	int err;
    315 	int flags = 0;
    316 
    317 	if (common_extent_args_process(argc, argv, 3, 6, "insert_node",
    318 				       usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
    319 		return;
    320 
    321 	cmd = argv[0];
    322 
    323 	extent.e_flags = 0;
    324 
    325 	while (argc > 2) {
    326 		if (!strcmp(argv[1], "--after")) {
    327 			argc--;
    328 			argv++;
    329 			flags |= EXT2_EXTENT_INSERT_AFTER;
    330 			continue;
    331 		}
    332 		if (!strcmp(argv[1], "--uninit")) {
    333 			argc--;
    334 			argv++;
    335 			extent.e_flags |= EXT2_EXTENT_FLAGS_UNINIT;
    336 			continue;
    337 		}
    338 		break;
    339 	}
    340 
    341 	if (argc != 4) {
    342 		fprintf(stderr, "usage: %s %s\n", cmd, usage);
    343 		return;
    344 	}
    345 
    346 	err = strtoblk(cmd, argv[1], "logical block", &extent.e_lblk);
    347 	if (err)
    348 		return;
    349 
    350 	extent.e_len = parse_ulong(argv[2], cmd, "length", &err);
    351 	if (err)
    352 		return;
    353 
    354 	err = strtoblk(cmd, argv[3], "physical block", &extent.e_pblk);
    355 	if (err)
    356 		return;
    357 
    358 	retval = ext2fs_extent_insert(current_handle, flags, &extent);
    359 	if (retval) {
    360 		com_err(cmd, retval, 0);
    361 		return;
    362 	}
    363 	generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
    364 }
    365 
    366 void do_set_bmap(int argc, char **argv)
    367 {
    368 	const char	*usage = "[--uninit] <lblk> <pblk>";
    369 	struct ext2fs_extent extent;
    370 	errcode_t	retval;
    371 	blk64_t		logical;
    372 	blk64_t		physical;
    373 	char		*cmd = argv[0];
    374 	int		flags = 0;
    375 	int		err;
    376 
    377 	if (common_extent_args_process(argc, argv, 3, 5, "set_bmap",
    378 				       usage, CHECK_FS_RW | CHECK_FS_BITMAPS))
    379 		return;
    380 
    381 	if (argc > 2 && !strcmp(argv[1], "--uninit")) {
    382 		argc--;
    383 		argv++;
    384 		flags |= EXT2_EXTENT_SET_BMAP_UNINIT;
    385 	}
    386 
    387 	if (argc != 3) {
    388 		fprintf(stderr, "Usage: %s %s\n", cmd, usage);
    389 		return;
    390 	}
    391 
    392 	err = strtoblk(cmd, argv[1], "logical block", &logical);
    393 	if (err)
    394 		return;
    395 
    396 	err = strtoblk(cmd, argv[2], "physical block", &physical);
    397 	if (err)
    398 		return;
    399 
    400 	retval = ext2fs_extent_set_bmap(current_handle, logical,
    401 					physical, flags);
    402 	if (retval) {
    403 		com_err(cmd, retval, 0);
    404 		return;
    405 	}
    406 
    407 	retval = ext2fs_extent_get(current_handle, EXT2_EXTENT_CURRENT,
    408 				   &extent);
    409 	if (retval)
    410 		return;
    411 	dbg_print_extent(0, &extent);
    412 }
    413 
    414 void do_print_all(int argc, char **argv)
    415 {
    416 	const char	*usage = "[--leaf-only|--reverse|--reverse-leaf]";
    417 	struct ext2fs_extent	extent;
    418 	errcode_t		retval;
    419 	errcode_t		end_err = EXT2_ET_EXTENT_NO_NEXT;
    420 	int			op = EXT2_EXTENT_NEXT;
    421 	int			first_op = EXT2_EXTENT_ROOT;
    422 
    423 
    424 	if (common_extent_args_process(argc, argv, 1, 2, "print_all",
    425 				       usage, 0))
    426 		return;
    427 
    428 	if (argc == 2) {
    429 		if (!strcmp(argv[1], "--leaf-only"))
    430 			op = EXT2_EXTENT_NEXT_LEAF;
    431 		else if (!strcmp(argv[1], "--reverse")) {
    432 			op = EXT2_EXTENT_PREV;
    433 			first_op = EXT2_EXTENT_LAST_LEAF;
    434 			end_err = EXT2_ET_EXTENT_NO_PREV;
    435 		} else if (!strcmp(argv[1], "--reverse-leaf")) {
    436 			op = EXT2_EXTENT_PREV_LEAF;
    437 			first_op = EXT2_EXTENT_LAST_LEAF;
    438 			end_err = EXT2_ET_EXTENT_NO_PREV;
    439 		} else {
    440 			fprintf(stderr, "Usage: %s %s\n", argv[0], usage);
    441 			return;
    442 		}
    443 	}
    444 
    445 	retval = ext2fs_extent_get(current_handle, first_op, &extent);
    446 	if (retval) {
    447 		com_err(argv[0], retval, 0);
    448 		return;
    449 	}
    450 	dbg_print_extent(0, &extent);
    451 
    452 	while (1) {
    453 		retval = ext2fs_extent_get(current_handle, op, &extent);
    454 		if (retval == end_err)
    455 			break;
    456 
    457 		if (retval) {
    458 			com_err(argv[0], retval, 0);
    459 			return;
    460 		}
    461 		dbg_print_extent(0, &extent);
    462 	}
    463 }
    464 
    465 void do_fix_parents(int argc, char **argv)
    466 {
    467 	errcode_t		retval;
    468 
    469 	if (common_extent_args_process(argc, argv, 1, 1, "fix_parents", "",
    470 				       CHECK_FS_RW))
    471 		return;
    472 
    473 	retval = ext2fs_extent_fix_parents(current_handle);
    474 	if (retval) {
    475 		com_err(argv[0], retval, 0);
    476 		return;
    477 	}
    478 }
    479 
    480 void do_info(int argc, char **argv)
    481 {
    482 	struct ext2fs_extent	extent;
    483 	struct ext2_extent_info	info;
    484 	errcode_t		retval;
    485 
    486 	if (common_extent_args_process(argc, argv, 1, 1, "info", "", 0))
    487 		return;
    488 
    489 	retval = ext2fs_extent_get_info(current_handle, &info);
    490 	if (retval) {
    491 		com_err(argv[0], retval, 0);
    492 		return;
    493 	}
    494 
    495 	retval = ext2fs_extent_get(current_handle,
    496 				   EXT2_EXTENT_CURRENT, &extent);
    497 	if (retval) {
    498 		com_err(argv[0], retval, 0);
    499 		return;
    500 	}
    501 
    502 	dbg_print_extent(0, &extent);
    503 
    504 	printf("Current handle location: %d/%d (max: %d, bytes %d), level %d/%d\n",
    505 	       info.curr_entry, info.num_entries, info.max_entries,
    506 	       info.bytes_avail, info.curr_level, info.max_depth);
    507 	printf("\tmax lblk: %llu, max pblk: %llu\n", info.max_lblk,
    508 	       info.max_pblk);
    509 	printf("\tmax_len: %u, max_uninit_len: %u\n", info.max_len,
    510 	       info.max_uninit_len);
    511 }
    512 
    513 void do_goto_block(int argc, char **argv)
    514 {
    515 	errcode_t		retval;
    516 	blk64_t			blk;
    517 	int			level = 0, err;
    518 
    519 	if (common_extent_args_process(argc, argv, 2, 3, "goto_block",
    520 				       "block [level]", 0))
    521 		return;
    522 
    523 	if (strtoblk(argv[0], argv[1], NULL, &blk))
    524 		return;
    525 
    526 	if (argc == 3) {
    527 		level = parse_ulong(argv[2], argv[0], "level", &err);
    528 		if (err)
    529 			return;
    530 	}
    531 
    532 	retval = ext2fs_extent_goto2(current_handle, level, (blk64_t) blk);
    533 
    534 	if (retval) {
    535 		com_err(argv[0], retval,
    536 			"while trying to go to block %llu, level %d",
    537 			(unsigned long long) blk, level);
    538 		return;
    539 	}
    540 
    541 	generic_goto_node(NULL, argc, argv, EXT2_EXTENT_CURRENT);
    542 }
    543