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