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