1 /* 2 * debugfs.c --- a program which allows you to attach an ext2fs 3 * filesystem and play with it. 4 * 5 * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed 6 * under the terms of the GNU Public License. 7 * 8 * Modifications by Robert Sanders <gt8134b (at) prism.gatech.edu> 9 */ 10 11 #include "config.h" 12 #include <stdio.h> 13 #include <unistd.h> 14 #include <stdlib.h> 15 #include <ctype.h> 16 #include <string.h> 17 #include <time.h> 18 #include <libgen.h> 19 #ifdef HAVE_GETOPT_H 20 #include <getopt.h> 21 #else 22 extern int optind; 23 extern char *optarg; 24 #endif 25 #ifdef HAVE_ERRNO_H 26 #include <errno.h> 27 #endif 28 #include <fcntl.h> 29 #ifdef HAVE_SYS_SYSMACROS_H 30 #include <sys/sysmacros.h> 31 #endif 32 33 #include "debugfs.h" 34 #include "uuid/uuid.h" 35 #include "e2p/e2p.h" 36 37 #include <ext2fs/ext2_ext_attr.h> 38 39 #include "../version.h" 40 #include "jfs_user.h" 41 #include "support/plausible.h" 42 43 #ifndef BUFSIZ 44 #define BUFSIZ 8192 45 #endif 46 47 #ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jbd-debug */ 48 int journal_enable_debug = -1; 49 #endif 50 51 ss_request_table *extra_cmds; 52 const char *debug_prog_name; 53 int ss_sci_idx; 54 55 ext2_filsys current_fs; 56 quota_ctx_t current_qctx; 57 ext2_ino_t root, cwd; 58 int no_copy_xattrs; 59 60 static int debugfs_setup_tdb(const char *device_name, char *undo_file, 61 io_manager *io_ptr) 62 { 63 errcode_t retval = ENOMEM; 64 const char *tdb_dir = NULL; 65 char *tdb_file = NULL; 66 char *dev_name, *tmp_name; 67 68 /* (re)open a specific undo file */ 69 if (undo_file && undo_file[0] != 0) { 70 retval = set_undo_io_backing_manager(*io_ptr); 71 if (retval) 72 goto err; 73 *io_ptr = undo_io_manager; 74 retval = set_undo_io_backup_file(undo_file); 75 if (retval) 76 goto err; 77 printf("Overwriting existing filesystem; this can be undone " 78 "using the command:\n" 79 " e2undo %s %s\n\n", 80 undo_file, device_name); 81 return retval; 82 } 83 84 /* 85 * Configuration via a conf file would be 86 * nice 87 */ 88 tdb_dir = ss_safe_getenv("E2FSPROGS_UNDO_DIR"); 89 if (!tdb_dir) 90 tdb_dir = "/var/lib/e2fsprogs"; 91 92 if (!strcmp(tdb_dir, "none") || (tdb_dir[0] == 0) || 93 access(tdb_dir, W_OK)) 94 return 0; 95 96 tmp_name = strdup(device_name); 97 if (!tmp_name) 98 goto errout; 99 dev_name = basename(tmp_name); 100 tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1); 101 if (!tdb_file) { 102 free(tmp_name); 103 goto errout; 104 } 105 sprintf(tdb_file, "%s/debugfs-%s.e2undo", tdb_dir, dev_name); 106 free(tmp_name); 107 108 if ((unlink(tdb_file) < 0) && (errno != ENOENT)) { 109 retval = errno; 110 com_err("debugfs", retval, 111 "while trying to delete %s", tdb_file); 112 goto errout; 113 } 114 115 retval = set_undo_io_backing_manager(*io_ptr); 116 if (retval) 117 goto errout; 118 *io_ptr = undo_io_manager; 119 retval = set_undo_io_backup_file(tdb_file); 120 if (retval) 121 goto errout; 122 printf("Overwriting existing filesystem; this can be undone " 123 "using the command:\n" 124 " e2undo %s %s\n\n", tdb_file, device_name); 125 126 free(tdb_file); 127 return 0; 128 errout: 129 free(tdb_file); 130 err: 131 com_err("debugfs", retval, "while trying to setup undo file\n"); 132 return retval; 133 } 134 135 static void open_filesystem(char *device, int open_flags, blk64_t superblock, 136 blk64_t blocksize, int catastrophic, 137 char *data_filename, char *undo_file) 138 { 139 int retval; 140 io_channel data_io = 0; 141 io_manager io_ptr = unix_io_manager; 142 143 if (superblock != 0 && blocksize == 0) { 144 com_err(device, 0, "if you specify the superblock, you must also specify the block size"); 145 current_fs = NULL; 146 return; 147 } 148 149 if (data_filename) { 150 if ((open_flags & EXT2_FLAG_IMAGE_FILE) == 0) { 151 com_err(device, 0, 152 "The -d option is only valid when reading an e2image file"); 153 current_fs = NULL; 154 return; 155 } 156 retval = unix_io_manager->open(data_filename, 0, &data_io); 157 if (retval) { 158 com_err(data_filename, 0, "while opening data source"); 159 current_fs = NULL; 160 return; 161 } 162 } 163 164 if (catastrophic) 165 open_flags |= EXT2_FLAG_SKIP_MMP | EXT2_FLAG_IGNORE_SB_ERRORS; 166 167 if (undo_file) { 168 retval = debugfs_setup_tdb(device, undo_file, &io_ptr); 169 if (retval) 170 exit(1); 171 } 172 173 try_open_again: 174 retval = ext2fs_open(device, open_flags, superblock, blocksize, 175 io_ptr, ¤t_fs); 176 if (retval && (retval == EXT2_ET_SB_CSUM_INVALID) && 177 !(open_flags & EXT2_FLAG_IGNORE_CSUM_ERRORS)) { 178 open_flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; 179 printf("Checksum errors in superblock! Retrying...\n"); 180 goto try_open_again; 181 } 182 if (retval) { 183 com_err(debug_prog_name, retval, 184 "while trying to open %s", device); 185 if (retval == EXT2_ET_BAD_MAGIC) 186 check_plausibility(device, CHECK_FS_EXIST, NULL); 187 current_fs = NULL; 188 return; 189 } 190 current_fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; 191 192 if (catastrophic) 193 com_err(device, 0, "catastrophic mode - not reading inode or group bitmaps"); 194 else { 195 retval = ext2fs_read_bitmaps(current_fs); 196 if (retval) { 197 com_err(device, retval, 198 "while reading allocation bitmaps"); 199 goto errout; 200 } 201 } 202 203 if (data_io) { 204 retval = ext2fs_set_data_io(current_fs, data_io); 205 if (retval) { 206 com_err(device, retval, 207 "while setting data source"); 208 goto errout; 209 } 210 } 211 212 root = cwd = EXT2_ROOT_INO; 213 return; 214 215 errout: 216 retval = ext2fs_close_free(¤t_fs); 217 if (retval) 218 com_err(device, retval, "while trying to close filesystem"); 219 } 220 221 void do_open_filesys(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)), 222 void *infop EXT2FS_ATTR((unused))) 223 { 224 int c, err; 225 int catastrophic = 0; 226 blk64_t superblock = 0; 227 blk64_t blocksize = 0; 228 int open_flags = EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS; 229 char *data_filename = 0; 230 char *undo_file = NULL; 231 232 reset_getopt(); 233 while ((c = getopt(argc, argv, "iwfecb:s:d:Dz:")) != EOF) { 234 switch (c) { 235 case 'i': 236 open_flags |= EXT2_FLAG_IMAGE_FILE; 237 break; 238 case 'w': 239 #ifdef READ_ONLY 240 goto print_usage; 241 #else 242 open_flags |= EXT2_FLAG_RW; 243 #endif /* READ_ONLY */ 244 break; 245 case 'f': 246 open_flags |= EXT2_FLAG_FORCE; 247 break; 248 case 'e': 249 open_flags |= EXT2_FLAG_EXCLUSIVE; 250 break; 251 case 'c': 252 catastrophic = 1; 253 break; 254 case 'd': 255 data_filename = optarg; 256 break; 257 case 'D': 258 open_flags |= EXT2_FLAG_DIRECT_IO; 259 break; 260 case 'b': 261 blocksize = parse_ulong(optarg, argv[0], 262 "block size", &err); 263 if (err) 264 return; 265 break; 266 case 's': 267 err = strtoblk(argv[0], optarg, 268 "superblock block number", &superblock); 269 if (err) 270 return; 271 break; 272 case 'z': 273 undo_file = optarg; 274 break; 275 default: 276 goto print_usage; 277 } 278 } 279 if (optind != argc-1) { 280 goto print_usage; 281 } 282 if (check_fs_not_open(argv[0])) 283 return; 284 open_filesystem(argv[optind], open_flags, 285 superblock, blocksize, catastrophic, 286 data_filename, undo_file); 287 return; 288 289 print_usage: 290 fprintf(stderr, "%s: Usage: open [-s superblock] [-b blocksize] " 291 "[-d image_filename] [-z undo_file] [-c] [-i] [-f] [-e] [-D] " 292 #ifndef READ_ONLY 293 "[-w] " 294 #endif 295 "<device>\n", argv[0]); 296 } 297 298 void do_lcd(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)), 299 void *infop EXT2FS_ATTR((unused))) 300 { 301 if (argc != 2) { 302 com_err(argv[0], 0, "Usage: %s %s", argv[0], "<native dir>"); 303 return; 304 } 305 306 if (chdir(argv[1]) == -1) { 307 com_err(argv[0], errno, 308 "while trying to change native directory to %s", 309 argv[1]); 310 return; 311 } 312 } 313 314 static void close_filesystem(NOARGS) 315 { 316 int retval; 317 318 if (current_fs->flags & EXT2_FLAG_IB_DIRTY) { 319 retval = ext2fs_write_inode_bitmap(current_fs); 320 if (retval) 321 com_err("ext2fs_write_inode_bitmap", retval, 0); 322 } 323 if (current_fs->flags & EXT2_FLAG_BB_DIRTY) { 324 retval = ext2fs_write_block_bitmap(current_fs); 325 if (retval) 326 com_err("ext2fs_write_block_bitmap", retval, 0); 327 } 328 if (current_qctx) 329 quota_release_context(¤t_qctx); 330 retval = ext2fs_close_free(¤t_fs); 331 if (retval) 332 com_err("ext2fs_close", retval, 0); 333 return; 334 } 335 336 void do_close_filesys(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)), 337 void *infop EXT2FS_ATTR((unused))) 338 { 339 int c; 340 341 if (check_fs_open(argv[0])) 342 return; 343 344 reset_getopt(); 345 while ((c = getopt (argc, argv, "a")) != EOF) { 346 switch (c) { 347 case 'a': 348 current_fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; 349 break; 350 default: 351 goto print_usage; 352 } 353 } 354 355 if (argc > optind) { 356 print_usage: 357 com_err(0, 0, "Usage: close_filesys [-a]"); 358 return; 359 } 360 361 close_filesystem(); 362 } 363 364 #ifndef READ_ONLY 365 void do_init_filesys(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)), 366 void *infop EXT2FS_ATTR((unused))) 367 { 368 struct ext2_super_block param; 369 errcode_t retval; 370 int err; 371 blk64_t blocks; 372 373 if (common_args_process(argc, argv, 3, 3, "initialize", 374 "<device> <blocks>", CHECK_FS_NOTOPEN)) 375 return; 376 377 memset(¶m, 0, sizeof(struct ext2_super_block)); 378 err = strtoblk(argv[0], argv[2], "blocks count", &blocks); 379 if (err) 380 return; 381 ext2fs_blocks_count_set(¶m, blocks); 382 retval = ext2fs_initialize(argv[1], 0, ¶m, 383 unix_io_manager, ¤t_fs); 384 if (retval) { 385 com_err(argv[1], retval, "while initializing filesystem"); 386 current_fs = NULL; 387 return; 388 } 389 root = cwd = EXT2_ROOT_INO; 390 return; 391 } 392 393 static void print_features(struct ext2_super_block * s, FILE *f) 394 { 395 int i, j, printed=0; 396 __u32 *mask = &s->s_feature_compat, m; 397 398 fputs("Filesystem features:", f); 399 for (i=0; i <3; i++,mask++) { 400 for (j=0,m=1; j < 32; j++, m<<=1) { 401 if (*mask & m) { 402 fprintf(f, " %s", e2p_feature2string(i, m)); 403 printed++; 404 } 405 } 406 } 407 if (printed == 0) 408 fputs("(none)", f); 409 fputs("\n", f); 410 } 411 #endif /* READ_ONLY */ 412 413 static void print_bg_opts(ext2_filsys fs, dgrp_t group, int mask, 414 const char *str, int *first, FILE *f) 415 { 416 if (ext2fs_bg_flags_test(fs, group, mask)) { 417 if (*first) { 418 fputs(" [", f); 419 *first = 0; 420 } else 421 fputs(", ", f); 422 fputs(str, f); 423 } 424 } 425 426 void do_show_super_stats(int argc, char *argv[], 427 int sci_idx EXT2FS_ATTR((unused)), 428 void *infop EXT2FS_ATTR((unused))) 429 { 430 const char *units ="block"; 431 dgrp_t i; 432 FILE *out; 433 int c, header_only = 0; 434 int numdirs = 0, first, gdt_csum; 435 436 reset_getopt(); 437 while ((c = getopt (argc, argv, "h")) != EOF) { 438 switch (c) { 439 case 'h': 440 header_only++; 441 break; 442 default: 443 goto print_usage; 444 } 445 } 446 if (optind != argc) { 447 goto print_usage; 448 } 449 if (check_fs_open(argv[0])) 450 return; 451 out = open_pager(); 452 453 if (ext2fs_has_feature_bigalloc(current_fs->super)) 454 units = "cluster"; 455 456 list_super2(current_fs->super, out); 457 if (ext2fs_has_feature_metadata_csum(current_fs->super) && 458 !ext2fs_superblock_csum_verify(current_fs, 459 current_fs->super)) { 460 __u32 orig_csum = current_fs->super->s_checksum; 461 462 ext2fs_superblock_csum_set(current_fs, 463 current_fs->super); 464 fprintf(out, "Expected Checksum: 0x%08x\n", 465 current_fs->super->s_checksum); 466 current_fs->super->s_checksum = orig_csum; 467 } 468 for (i=0; i < current_fs->group_desc_count; i++) 469 numdirs += ext2fs_bg_used_dirs_count(current_fs, i); 470 fprintf(out, "Directories: %d\n", numdirs); 471 472 if (header_only) { 473 close_pager(out); 474 return; 475 } 476 477 gdt_csum = ext2fs_has_group_desc_csum(current_fs); 478 for (i = 0; i < current_fs->group_desc_count; i++) { 479 fprintf(out, " Group %2d: block bitmap at %llu, " 480 "inode bitmap at %llu, " 481 "inode table at %llu\n" 482 " %u free %s%s, " 483 "%u free %s, " 484 "%u used %s%s", 485 i, ext2fs_block_bitmap_loc(current_fs, i), 486 ext2fs_inode_bitmap_loc(current_fs, i), 487 ext2fs_inode_table_loc(current_fs, i), 488 ext2fs_bg_free_blocks_count(current_fs, i), units, 489 ext2fs_bg_free_blocks_count(current_fs, i) != 1 ? 490 "s" : "", 491 ext2fs_bg_free_inodes_count(current_fs, i), 492 ext2fs_bg_free_inodes_count(current_fs, i) != 1 ? 493 "inodes" : "inode", 494 ext2fs_bg_used_dirs_count(current_fs, i), 495 ext2fs_bg_used_dirs_count(current_fs, i) != 1 ? "directories" 496 : "directory", gdt_csum ? ", " : "\n"); 497 if (gdt_csum) 498 fprintf(out, "%u unused %s\n", 499 ext2fs_bg_itable_unused(current_fs, i), 500 ext2fs_bg_itable_unused(current_fs, i) != 1 ? 501 "inodes" : "inode"); 502 first = 1; 503 print_bg_opts(current_fs, i, EXT2_BG_INODE_UNINIT, "Inode not init", 504 &first, out); 505 print_bg_opts(current_fs, i, EXT2_BG_BLOCK_UNINIT, "Block not init", 506 &first, out); 507 if (gdt_csum) { 508 fprintf(out, "%sChecksum 0x%04x", 509 first ? " [":", ", ext2fs_bg_checksum(current_fs, i)); 510 first = 0; 511 } 512 if (!first) 513 fputs("]\n", out); 514 } 515 close_pager(out); 516 return; 517 print_usage: 518 fprintf(stderr, "%s: Usage: show_super_stats [-h]\n", argv[0]); 519 } 520 521 #ifndef READ_ONLY 522 void do_dirty_filesys(int argc EXT2FS_ATTR((unused)), 523 char **argv EXT2FS_ATTR((unused)), 524 int sci_idx EXT2FS_ATTR((unused)), 525 void *infop EXT2FS_ATTR((unused))) 526 { 527 if (check_fs_open(argv[0])) 528 return; 529 if (check_fs_read_write(argv[0])) 530 return; 531 532 if (argv[1] && !strcmp(argv[1], "-clean")) 533 current_fs->super->s_state |= EXT2_VALID_FS; 534 else 535 current_fs->super->s_state &= ~EXT2_VALID_FS; 536 ext2fs_mark_super_dirty(current_fs); 537 } 538 #endif /* READ_ONLY */ 539 540 struct list_blocks_struct { 541 FILE *f; 542 e2_blkcnt_t total; 543 blk64_t first_block, last_block; 544 e2_blkcnt_t first_bcnt, last_bcnt; 545 e2_blkcnt_t first; 546 }; 547 548 static void finish_range(struct list_blocks_struct *lb) 549 { 550 if (lb->first_block == 0) 551 return; 552 if (lb->first) 553 lb->first = 0; 554 else 555 fprintf(lb->f, ", "); 556 if (lb->first_block == lb->last_block) 557 fprintf(lb->f, "(%lld):%llu", 558 (long long)lb->first_bcnt, lb->first_block); 559 else 560 fprintf(lb->f, "(%lld-%lld):%llu-%llu", 561 (long long)lb->first_bcnt, (long long)lb->last_bcnt, 562 lb->first_block, lb->last_block); 563 lb->first_block = 0; 564 } 565 566 static int list_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)), 567 blk64_t *blocknr, e2_blkcnt_t blockcnt, 568 blk64_t ref_block EXT2FS_ATTR((unused)), 569 int ref_offset EXT2FS_ATTR((unused)), 570 void *private) 571 { 572 struct list_blocks_struct *lb = (struct list_blocks_struct *) private; 573 574 lb->total++; 575 if (blockcnt >= 0) { 576 /* 577 * See if we can add on to the existing range (if it exists) 578 */ 579 if (lb->first_block && 580 (lb->last_block+1 == *blocknr) && 581 (lb->last_bcnt+1 == blockcnt)) { 582 lb->last_block = *blocknr; 583 lb->last_bcnt = blockcnt; 584 return 0; 585 } 586 /* 587 * Start a new range. 588 */ 589 finish_range(lb); 590 lb->first_block = lb->last_block = *blocknr; 591 lb->first_bcnt = lb->last_bcnt = blockcnt; 592 return 0; 593 } 594 /* 595 * Not a normal block. Always force a new range. 596 */ 597 finish_range(lb); 598 if (lb->first) 599 lb->first = 0; 600 else 601 fprintf(lb->f, ", "); 602 if (blockcnt == -1) 603 fprintf(lb->f, "(IND):%llu", (unsigned long long) *blocknr); 604 else if (blockcnt == -2) 605 fprintf(lb->f, "(DIND):%llu", (unsigned long long) *blocknr); 606 else if (blockcnt == -3) 607 fprintf(lb->f, "(TIND):%llu", (unsigned long long) *blocknr); 608 return 0; 609 } 610 611 static void internal_dump_inode_extra(FILE *out, 612 const char *prefix EXT2FS_ATTR((unused)), 613 ext2_ino_t inode_num EXT2FS_ATTR((unused)), 614 struct ext2_inode_large *inode) 615 { 616 fprintf(out, "Size of extra inode fields: %u\n", inode->i_extra_isize); 617 if (inode->i_extra_isize > EXT2_INODE_SIZE(current_fs->super) - 618 EXT2_GOOD_OLD_INODE_SIZE) { 619 fprintf(stderr, "invalid inode->i_extra_isize (%u)\n", 620 inode->i_extra_isize); 621 return; 622 } 623 } 624 625 static void dump_blocks(FILE *f, const char *prefix, ext2_ino_t inode) 626 { 627 struct list_blocks_struct lb; 628 629 fprintf(f, "%sBLOCKS:\n%s", prefix, prefix); 630 lb.total = 0; 631 lb.first_block = 0; 632 lb.f = f; 633 lb.first = 1; 634 ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL, 635 list_blocks_proc, (void *)&lb); 636 finish_range(&lb); 637 if (lb.total) 638 fprintf(f, "\n%sTOTAL: %lld\n", prefix, (long long)lb.total); 639 fprintf(f,"\n"); 640 } 641 642 static int int_log10(unsigned long long arg) 643 { 644 int l = 0; 645 646 arg = arg / 10; 647 while (arg) { 648 l++; 649 arg = arg / 10; 650 } 651 return l; 652 } 653 654 #define DUMP_LEAF_EXTENTS 0x01 655 #define DUMP_NODE_EXTENTS 0x02 656 #define DUMP_EXTENT_TABLE 0x04 657 658 static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino, 659 int flags, int logical_width, int physical_width) 660 { 661 ext2_extent_handle_t handle; 662 struct ext2fs_extent extent; 663 struct ext2_extent_info info; 664 int op = EXT2_EXTENT_ROOT; 665 unsigned int printed = 0; 666 errcode_t errcode; 667 668 errcode = ext2fs_extent_open(current_fs, ino, &handle); 669 if (errcode) 670 return; 671 672 if (flags & DUMP_EXTENT_TABLE) 673 fprintf(f, "Level Entries %*s %*s Length Flags\n", 674 (logical_width*2)+3, "Logical", 675 (physical_width*2)+3, "Physical"); 676 else 677 fprintf(f, "%sEXTENTS:\n%s", prefix, prefix); 678 679 while (1) { 680 errcode = ext2fs_extent_get(handle, op, &extent); 681 682 if (errcode) 683 break; 684 685 op = EXT2_EXTENT_NEXT; 686 687 if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) 688 continue; 689 690 if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) { 691 if ((flags & DUMP_LEAF_EXTENTS) == 0) 692 continue; 693 } else { 694 if ((flags & DUMP_NODE_EXTENTS) == 0) 695 continue; 696 } 697 698 errcode = ext2fs_extent_get_info(handle, &info); 699 if (errcode) 700 continue; 701 702 if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) { 703 if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) 704 continue; 705 706 if (flags & DUMP_EXTENT_TABLE) { 707 fprintf(f, "%2d/%2d %3d/%3d %*llu - %*llu " 708 "%*llu%*s %6u\n", 709 info.curr_level, info.max_depth, 710 info.curr_entry, info.num_entries, 711 logical_width, 712 extent.e_lblk, 713 logical_width, 714 extent.e_lblk + (extent.e_len - 1), 715 physical_width, 716 extent.e_pblk, 717 physical_width+3, "", extent.e_len); 718 continue; 719 } 720 721 fprintf(f, "%s(ETB%d):%lld", 722 printed ? ", " : "", info.curr_level, 723 extent.e_pblk); 724 printed = 1; 725 continue; 726 } 727 728 if (flags & DUMP_EXTENT_TABLE) { 729 fprintf(f, "%2d/%2d %3d/%3d %*llu - %*llu " 730 "%*llu - %*llu %6u %s\n", 731 info.curr_level, info.max_depth, 732 info.curr_entry, info.num_entries, 733 logical_width, 734 extent.e_lblk, 735 logical_width, 736 extent.e_lblk + (extent.e_len - 1), 737 physical_width, 738 extent.e_pblk, 739 physical_width, 740 extent.e_pblk + (extent.e_len - 1), 741 extent.e_len, 742 extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? 743 "Uninit" : ""); 744 continue; 745 } 746 747 if (extent.e_len == 0) 748 continue; 749 else if (extent.e_len == 1) 750 fprintf(f, 751 "%s(%lld%s):%lld", 752 printed ? ", " : "", 753 extent.e_lblk, 754 extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? 755 "[u]" : "", 756 extent.e_pblk); 757 else 758 fprintf(f, 759 "%s(%lld-%lld%s):%lld-%lld", 760 printed ? ", " : "", 761 extent.e_lblk, 762 extent.e_lblk + (extent.e_len - 1), 763 extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ? 764 "[u]" : "", 765 extent.e_pblk, 766 extent.e_pblk + (extent.e_len - 1)); 767 printed = 1; 768 } 769 if (printed) 770 fprintf(f, "\n"); 771 ext2fs_extent_free(handle); 772 } 773 774 static void dump_inline_data(FILE *out, const char *prefix, ext2_ino_t inode_num) 775 { 776 errcode_t retval; 777 size_t size; 778 779 retval = ext2fs_inline_data_size(current_fs, inode_num, &size); 780 if (!retval) 781 fprintf(out, "%sSize of inline data: %zu\n", prefix, size); 782 } 783 784 static void dump_inline_symlink(FILE *out, ext2_ino_t inode_num, 785 struct ext2_inode *inode, const char *prefix) 786 { 787 errcode_t retval; 788 char *buf = NULL; 789 size_t size; 790 791 retval = ext2fs_inline_data_size(current_fs, inode_num, &size); 792 if (retval) 793 goto out; 794 795 retval = ext2fs_get_memzero(size + 1, &buf); 796 if (retval) 797 goto out; 798 799 retval = ext2fs_inline_data_get(current_fs, inode_num, 800 inode, buf, &size); 801 if (retval) 802 goto out; 803 804 fprintf(out, "%sFast link dest: \"%.*s\"\n", prefix, 805 (int)size, buf); 806 out: 807 if (buf) 808 ext2fs_free_mem(&buf); 809 if (retval) 810 com_err(__func__, retval, "while dumping link destination"); 811 } 812 813 void internal_dump_inode(FILE *out, const char *prefix, 814 ext2_ino_t inode_num, struct ext2_inode *inode, 815 int do_dump_blocks) 816 { 817 const char *i_type; 818 char frag, fsize; 819 int os = current_fs->super->s_creator_os; 820 struct ext2_inode_large *large_inode; 821 int is_large_inode = 0; 822 823 if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE) 824 is_large_inode = 1; 825 large_inode = (struct ext2_inode_large *) inode; 826 827 if (LINUX_S_ISDIR(inode->i_mode)) i_type = "directory"; 828 else if (LINUX_S_ISREG(inode->i_mode)) i_type = "regular"; 829 else if (LINUX_S_ISLNK(inode->i_mode)) i_type = "symlink"; 830 else if (LINUX_S_ISBLK(inode->i_mode)) i_type = "block special"; 831 else if (LINUX_S_ISCHR(inode->i_mode)) i_type = "character special"; 832 else if (LINUX_S_ISFIFO(inode->i_mode)) i_type = "FIFO"; 833 else if (LINUX_S_ISSOCK(inode->i_mode)) i_type = "socket"; 834 else i_type = "bad type"; 835 fprintf(out, "%sInode: %u Type: %s ", prefix, inode_num, i_type); 836 fprintf(out, "%sMode: 0%03o Flags: 0x%x\n", 837 prefix, inode->i_mode & 07777, inode->i_flags); 838 if (is_large_inode && large_inode->i_extra_isize >= 24) { 839 fprintf(out, "%sGeneration: %u Version: 0x%08x:%08x\n", 840 prefix, inode->i_generation, large_inode->i_version_hi, 841 inode->osd1.linux1.l_i_version); 842 } else { 843 fprintf(out, "%sGeneration: %u Version: 0x%08x\n", prefix, 844 inode->i_generation, inode->osd1.linux1.l_i_version); 845 } 846 fprintf(out, "%sUser: %5d Group: %5d", 847 prefix, inode_uid(*inode), inode_gid(*inode)); 848 if (is_large_inode && large_inode->i_extra_isize >= 32) 849 fprintf(out, " Project: %5d", large_inode->i_projid); 850 fputs(" Size: ", out); 851 if (LINUX_S_ISREG(inode->i_mode)) 852 fprintf(out, "%llu\n", EXT2_I_SIZE(inode)); 853 else 854 fprintf(out, "%d\n", inode->i_size); 855 if (os == EXT2_OS_HURD) 856 fprintf(out, 857 "%sFile ACL: %d Translator: %d\n", 858 prefix, 859 inode->i_file_acl, 860 inode->osd1.hurd1.h_i_translator); 861 else 862 fprintf(out, "%sFile ACL: %llu\n", 863 prefix, 864 inode->i_file_acl | ((long long) 865 (inode->osd2.linux2.l_i_file_acl_high) << 32)); 866 if (os != EXT2_OS_HURD) 867 fprintf(out, "%sLinks: %d Blockcount: %llu\n", 868 prefix, inode->i_links_count, 869 (((unsigned long long) 870 inode->osd2.linux2.l_i_blocks_hi << 32)) + 871 inode->i_blocks); 872 else 873 fprintf(out, "%sLinks: %d Blockcount: %u\n", 874 prefix, inode->i_links_count, inode->i_blocks); 875 switch (os) { 876 case EXT2_OS_HURD: 877 frag = inode->osd2.hurd2.h_i_frag; 878 fsize = inode->osd2.hurd2.h_i_fsize; 879 break; 880 default: 881 frag = fsize = 0; 882 } 883 fprintf(out, "%sFragment: Address: %d Number: %d Size: %d\n", 884 prefix, inode->i_faddr, frag, fsize); 885 if (is_large_inode && large_inode->i_extra_isize >= 24) { 886 fprintf(out, "%s ctime: 0x%08x:%08x -- %s", prefix, 887 inode->i_ctime, large_inode->i_ctime_extra, 888 inode_time_to_string(inode->i_ctime, 889 large_inode->i_ctime_extra)); 890 fprintf(out, "%s atime: 0x%08x:%08x -- %s", prefix, 891 inode->i_atime, large_inode->i_atime_extra, 892 inode_time_to_string(inode->i_atime, 893 large_inode->i_atime_extra)); 894 fprintf(out, "%s mtime: 0x%08x:%08x -- %s", prefix, 895 inode->i_mtime, large_inode->i_mtime_extra, 896 inode_time_to_string(inode->i_mtime, 897 large_inode->i_mtime_extra)); 898 fprintf(out, "%scrtime: 0x%08x:%08x -- %s", prefix, 899 large_inode->i_crtime, large_inode->i_crtime_extra, 900 inode_time_to_string(large_inode->i_crtime, 901 large_inode->i_crtime_extra)); 902 if (inode->i_dtime) 903 fprintf(out, "%s dtime: 0x%08x:(%08x) -- %s", prefix, 904 large_inode->i_dtime, large_inode->i_ctime_extra, 905 inode_time_to_string(inode->i_dtime, 906 large_inode->i_ctime_extra)); 907 } else { 908 fprintf(out, "%sctime: 0x%08x -- %s", prefix, inode->i_ctime, 909 time_to_string((__s32) inode->i_ctime)); 910 fprintf(out, "%satime: 0x%08x -- %s", prefix, inode->i_atime, 911 time_to_string((__s32) inode->i_atime)); 912 fprintf(out, "%smtime: 0x%08x -- %s", prefix, inode->i_mtime, 913 time_to_string((__s32) inode->i_mtime)); 914 if (inode->i_dtime) 915 fprintf(out, "%sdtime: 0x%08x -- %s", prefix, 916 inode->i_dtime, 917 time_to_string((__s32) inode->i_dtime)); 918 } 919 if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE) 920 internal_dump_inode_extra(out, prefix, inode_num, 921 (struct ext2_inode_large *) inode); 922 dump_inode_attributes(out, inode_num); 923 if (ext2fs_has_feature_metadata_csum(current_fs->super)) { 924 __u32 crc = inode->i_checksum_lo; 925 if (is_large_inode && 926 large_inode->i_extra_isize >= 927 (offsetof(struct ext2_inode_large, 928 i_checksum_hi) - 929 EXT2_GOOD_OLD_INODE_SIZE)) 930 crc |= ((__u32)large_inode->i_checksum_hi) << 16; 931 fprintf(out, "Inode checksum: 0x%08x\n", crc); 932 } 933 934 if (LINUX_S_ISLNK(inode->i_mode) && ext2fs_is_fast_symlink(inode)) 935 fprintf(out, "%sFast link dest: \"%.*s\"\n", prefix, 936 (int)EXT2_I_SIZE(inode), (char *)inode->i_block); 937 else if (LINUX_S_ISLNK(inode->i_mode) && 938 (inode->i_flags & EXT4_INLINE_DATA_FL)) 939 dump_inline_symlink(out, inode_num, inode, prefix); 940 else if (LINUX_S_ISBLK(inode->i_mode) || LINUX_S_ISCHR(inode->i_mode)) { 941 int major, minor; 942 const char *devnote; 943 944 if (inode->i_block[0]) { 945 major = (inode->i_block[0] >> 8) & 255; 946 minor = inode->i_block[0] & 255; 947 devnote = ""; 948 } else { 949 major = (inode->i_block[1] & 0xfff00) >> 8; 950 minor = ((inode->i_block[1] & 0xff) | 951 ((inode->i_block[1] >> 12) & 0xfff00)); 952 devnote = "(New-style) "; 953 } 954 fprintf(out, "%sDevice major/minor number: %02d:%02d (hex %02x:%02x)\n", 955 devnote, major, minor, major, minor); 956 } else if (do_dump_blocks) { 957 if (inode->i_flags & EXT4_EXTENTS_FL) 958 dump_extents(out, prefix, inode_num, 959 DUMP_LEAF_EXTENTS|DUMP_NODE_EXTENTS, 0, 0); 960 else if (inode->i_flags & EXT4_INLINE_DATA_FL) 961 dump_inline_data(out, prefix, inode_num); 962 else 963 dump_blocks(out, prefix, inode_num); 964 } 965 } 966 967 static void dump_inode(ext2_ino_t inode_num, struct ext2_inode *inode) 968 { 969 FILE *out; 970 971 out = open_pager(); 972 internal_dump_inode(out, "", inode_num, inode, 1); 973 close_pager(out); 974 } 975 976 void do_stat(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 977 void *infop EXT2FS_ATTR((unused))) 978 { 979 ext2_ino_t inode; 980 struct ext2_inode * inode_buf; 981 982 if (check_fs_open(argv[0])) 983 return; 984 985 inode_buf = (struct ext2_inode *) 986 malloc(EXT2_INODE_SIZE(current_fs->super)); 987 if (!inode_buf) { 988 fprintf(stderr, "do_stat: can't allocate buffer\n"); 989 return; 990 } 991 992 if (common_inode_args_process(argc, argv, &inode, 0)) { 993 free(inode_buf); 994 return; 995 } 996 997 if (debugfs_read_inode_full(inode, inode_buf, argv[0], 998 EXT2_INODE_SIZE(current_fs->super))) { 999 free(inode_buf); 1000 return; 1001 } 1002 1003 dump_inode(inode, inode_buf); 1004 free(inode_buf); 1005 return; 1006 } 1007 1008 void do_dump_extents(int argc, char **argv, int sci_idx EXT2FS_ATTR((unused)), 1009 void *infop EXT2FS_ATTR((unused))) 1010 { 1011 struct ext2_inode inode; 1012 ext2_ino_t ino; 1013 FILE *out; 1014 int c, flags = 0; 1015 int logical_width; 1016 int physical_width; 1017 1018 reset_getopt(); 1019 while ((c = getopt(argc, argv, "nl")) != EOF) { 1020 switch (c) { 1021 case 'n': 1022 flags |= DUMP_NODE_EXTENTS; 1023 break; 1024 case 'l': 1025 flags |= DUMP_LEAF_EXTENTS; 1026 break; 1027 } 1028 } 1029 1030 if (argc != optind + 1) { 1031 com_err(0, 0, "Usage: dump_extents [-n] [-l] file"); 1032 return; 1033 } 1034 1035 if (flags == 0) 1036 flags = DUMP_NODE_EXTENTS | DUMP_LEAF_EXTENTS; 1037 flags |= DUMP_EXTENT_TABLE; 1038 1039 if (check_fs_open(argv[0])) 1040 return; 1041 1042 ino = string_to_inode(argv[optind]); 1043 if (ino == 0) 1044 return; 1045 1046 if (debugfs_read_inode(ino, &inode, argv[0])) 1047 return; 1048 1049 if ((inode.i_flags & EXT4_EXTENTS_FL) == 0) { 1050 fprintf(stderr, "%s: does not uses extent block maps\n", 1051 argv[optind]); 1052 return; 1053 } 1054 1055 logical_width = int_log10((EXT2_I_SIZE(&inode)+current_fs->blocksize-1)/ 1056 current_fs->blocksize) + 1; 1057 if (logical_width < 5) 1058 logical_width = 5; 1059 physical_width = int_log10(ext2fs_blocks_count(current_fs->super)) + 1; 1060 if (physical_width < 5) 1061 physical_width = 5; 1062 1063 out = open_pager(); 1064 dump_extents(out, "", ino, flags, logical_width, physical_width); 1065 close_pager(out); 1066 return; 1067 } 1068 1069 static int print_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)), 1070 blk64_t *blocknr, 1071 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 1072 blk64_t ref_block EXT2FS_ATTR((unused)), 1073 int ref_offset EXT2FS_ATTR((unused)), 1074 void *private EXT2FS_ATTR((unused))) 1075 { 1076 printf("%llu ", *blocknr); 1077 return 0; 1078 } 1079 1080 void do_blocks(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1081 void *infop EXT2FS_ATTR((unused))) 1082 { 1083 ext2_ino_t inode; 1084 1085 if (check_fs_open(argv[0])) 1086 return; 1087 1088 if (common_inode_args_process(argc, argv, &inode, 0)) { 1089 return; 1090 } 1091 1092 ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL, 1093 print_blocks_proc, NULL); 1094 fputc('\n', stdout); 1095 return; 1096 } 1097 1098 void do_chroot(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1099 void *infop EXT2FS_ATTR((unused))) 1100 { 1101 ext2_ino_t inode; 1102 int retval; 1103 1104 if (common_inode_args_process(argc, argv, &inode, 0)) 1105 return; 1106 1107 retval = ext2fs_check_directory(current_fs, inode); 1108 if (retval) { 1109 com_err(argv[1], retval, 0); 1110 return; 1111 } 1112 root = inode; 1113 } 1114 1115 #ifndef READ_ONLY 1116 void do_clri(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1117 void *infop EXT2FS_ATTR((unused))) 1118 { 1119 ext2_ino_t inode; 1120 struct ext2_inode inode_buf; 1121 1122 if (common_inode_args_process(argc, argv, &inode, CHECK_FS_RW)) 1123 return; 1124 1125 if (debugfs_read_inode(inode, &inode_buf, argv[0])) 1126 return; 1127 memset(&inode_buf, 0, sizeof(inode_buf)); 1128 if (debugfs_write_inode(inode, &inode_buf, argv[0])) 1129 return; 1130 } 1131 1132 void do_freei(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1133 void *infop EXT2FS_ATTR((unused))) 1134 { 1135 unsigned int len = 1; 1136 int err = 0; 1137 ext2_ino_t inode; 1138 1139 if (common_args_process(argc, argv, 2, 3, argv[0], "<file> [num]", 1140 CHECK_FS_RW | CHECK_FS_BITMAPS)) 1141 return; 1142 if (check_fs_read_write(argv[0])) 1143 return; 1144 1145 inode = string_to_inode(argv[1]); 1146 if (!inode) 1147 return; 1148 1149 if (argc == 3) { 1150 len = parse_ulong(argv[2], argv[0], "length", &err); 1151 if (err) 1152 return; 1153 } 1154 1155 if (len == 1 && 1156 !ext2fs_test_inode_bitmap2(current_fs->inode_map,inode)) 1157 com_err(argv[0], 0, "Warning: inode already clear"); 1158 while (len-- > 0) 1159 ext2fs_unmark_inode_bitmap2(current_fs->inode_map, inode++); 1160 ext2fs_mark_ib_dirty(current_fs); 1161 } 1162 1163 void do_seti(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1164 void *infop EXT2FS_ATTR((unused))) 1165 { 1166 unsigned int len = 1; 1167 int err = 0; 1168 ext2_ino_t inode; 1169 1170 if (common_args_process(argc, argv, 2, 3, argv[0], "<file> [num]", 1171 CHECK_FS_RW | CHECK_FS_BITMAPS)) 1172 return; 1173 if (check_fs_read_write(argv[0])) 1174 return; 1175 1176 inode = string_to_inode(argv[1]); 1177 if (!inode) 1178 return; 1179 1180 if (argc == 3) { 1181 len = parse_ulong(argv[2], argv[0], "length", &err); 1182 if (err) 1183 return; 1184 } 1185 1186 if ((len == 1) && 1187 ext2fs_test_inode_bitmap2(current_fs->inode_map,inode)) 1188 com_err(argv[0], 0, "Warning: inode already set"); 1189 while (len-- > 0) 1190 ext2fs_mark_inode_bitmap2(current_fs->inode_map, inode++); 1191 ext2fs_mark_ib_dirty(current_fs); 1192 } 1193 #endif /* READ_ONLY */ 1194 1195 void do_testi(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1196 void *infop EXT2FS_ATTR((unused))) 1197 { 1198 ext2_ino_t inode; 1199 1200 if (common_inode_args_process(argc, argv, &inode, CHECK_FS_BITMAPS)) 1201 return; 1202 1203 if (ext2fs_test_inode_bitmap2(current_fs->inode_map,inode)) 1204 printf("Inode %u is marked in use\n", inode); 1205 else 1206 printf("Inode %u is not in use\n", inode); 1207 } 1208 1209 #ifndef READ_ONLY 1210 void do_freeb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1211 void *infop EXT2FS_ATTR((unused))) 1212 { 1213 blk64_t block; 1214 blk64_t count = 1; 1215 1216 if (common_block_args_process(argc, argv, &block, &count)) 1217 return; 1218 if (check_fs_read_write(argv[0])) 1219 return; 1220 while (count-- > 0) { 1221 if (!ext2fs_test_block_bitmap2(current_fs->block_map,block)) 1222 com_err(argv[0], 0, "Warning: block %llu already clear", 1223 block); 1224 ext2fs_unmark_block_bitmap2(current_fs->block_map,block); 1225 block++; 1226 } 1227 ext2fs_mark_bb_dirty(current_fs); 1228 } 1229 1230 void do_setb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1231 void *infop EXT2FS_ATTR((unused))) 1232 { 1233 blk64_t block; 1234 blk64_t count = 1; 1235 1236 if (common_block_args_process(argc, argv, &block, &count)) 1237 return; 1238 if (check_fs_read_write(argv[0])) 1239 return; 1240 while (count-- > 0) { 1241 if (ext2fs_test_block_bitmap2(current_fs->block_map,block)) 1242 com_err(argv[0], 0, "Warning: block %llu already set", 1243 block); 1244 ext2fs_mark_block_bitmap2(current_fs->block_map,block); 1245 block++; 1246 } 1247 ext2fs_mark_bb_dirty(current_fs); 1248 } 1249 #endif /* READ_ONLY */ 1250 1251 void do_testb(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1252 void *infop EXT2FS_ATTR((unused))) 1253 { 1254 blk64_t block; 1255 blk64_t count = 1; 1256 1257 if (common_block_args_process(argc, argv, &block, &count)) 1258 return; 1259 while (count-- > 0) { 1260 if (ext2fs_test_block_bitmap2(current_fs->block_map,block)) 1261 printf("Block %llu marked in use\n", block); 1262 else 1263 printf("Block %llu not in use\n", block); 1264 block++; 1265 } 1266 } 1267 1268 #ifndef READ_ONLY 1269 static void modify_u8(char *com, const char *prompt, 1270 const char *format, __u8 *val) 1271 { 1272 char buf[200]; 1273 unsigned long v; 1274 char *tmp; 1275 1276 sprintf(buf, format, *val); 1277 printf("%30s [%s] ", prompt, buf); 1278 if (!fgets(buf, sizeof(buf), stdin)) 1279 return; 1280 if (buf[strlen (buf) - 1] == '\n') 1281 buf[strlen (buf) - 1] = '\0'; 1282 if (!buf[0]) 1283 return; 1284 v = strtoul(buf, &tmp, 0); 1285 if (*tmp) 1286 com_err(com, 0, "Bad value - %s", buf); 1287 else 1288 *val = v; 1289 } 1290 1291 static void modify_u16(char *com, const char *prompt, 1292 const char *format, __u16 *val) 1293 { 1294 char buf[200]; 1295 unsigned long v; 1296 char *tmp; 1297 1298 sprintf(buf, format, *val); 1299 printf("%30s [%s] ", prompt, buf); 1300 if (!fgets(buf, sizeof(buf), stdin)) 1301 return; 1302 if (buf[strlen (buf) - 1] == '\n') 1303 buf[strlen (buf) - 1] = '\0'; 1304 if (!buf[0]) 1305 return; 1306 v = strtoul(buf, &tmp, 0); 1307 if (*tmp) 1308 com_err(com, 0, "Bad value - %s", buf); 1309 else 1310 *val = v; 1311 } 1312 1313 static void modify_u32(char *com, const char *prompt, 1314 const char *format, __u32 *val) 1315 { 1316 char buf[200]; 1317 unsigned long v; 1318 char *tmp; 1319 1320 sprintf(buf, format, *val); 1321 printf("%30s [%s] ", prompt, buf); 1322 if (!fgets(buf, sizeof(buf), stdin)) 1323 return; 1324 if (buf[strlen (buf) - 1] == '\n') 1325 buf[strlen (buf) - 1] = '\0'; 1326 if (!buf[0]) 1327 return; 1328 v = strtoul(buf, &tmp, 0); 1329 if (*tmp) 1330 com_err(com, 0, "Bad value - %s", buf); 1331 else 1332 *val = v; 1333 } 1334 1335 1336 void do_modify_inode(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1337 void *infop EXT2FS_ATTR((unused))) 1338 { 1339 struct ext2_inode inode; 1340 ext2_ino_t inode_num; 1341 int i; 1342 unsigned char *frag, *fsize; 1343 char buf[80]; 1344 int os; 1345 const char *hex_format = "0x%x"; 1346 const char *octal_format = "0%o"; 1347 const char *decimal_format = "%d"; 1348 const char *unsignedlong_format = "%lu"; 1349 1350 if (common_inode_args_process(argc, argv, &inode_num, CHECK_FS_RW)) 1351 return; 1352 1353 os = current_fs->super->s_creator_os; 1354 1355 if (debugfs_read_inode(inode_num, &inode, argv[1])) 1356 return; 1357 1358 modify_u16(argv[0], "Mode", octal_format, &inode.i_mode); 1359 modify_u16(argv[0], "User ID", decimal_format, &inode.i_uid); 1360 modify_u16(argv[0], "Group ID", decimal_format, &inode.i_gid); 1361 modify_u32(argv[0], "Size", unsignedlong_format, &inode.i_size); 1362 modify_u32(argv[0], "Creation time", decimal_format, &inode.i_ctime); 1363 modify_u32(argv[0], "Modification time", decimal_format, &inode.i_mtime); 1364 modify_u32(argv[0], "Access time", decimal_format, &inode.i_atime); 1365 modify_u32(argv[0], "Deletion time", decimal_format, &inode.i_dtime); 1366 modify_u16(argv[0], "Link count", decimal_format, &inode.i_links_count); 1367 if (os == EXT2_OS_LINUX) 1368 modify_u16(argv[0], "Block count high", unsignedlong_format, 1369 &inode.osd2.linux2.l_i_blocks_hi); 1370 modify_u32(argv[0], "Block count", unsignedlong_format, &inode.i_blocks); 1371 modify_u32(argv[0], "File flags", hex_format, &inode.i_flags); 1372 modify_u32(argv[0], "Generation", hex_format, &inode.i_generation); 1373 #if 0 1374 modify_u32(argv[0], "Reserved1", decimal_format, &inode.i_reserved1); 1375 #endif 1376 modify_u32(argv[0], "File acl", decimal_format, &inode.i_file_acl); 1377 1378 modify_u32(argv[0], "High 32bits of size", decimal_format, 1379 &inode.i_size_high); 1380 1381 if (os == EXT2_OS_HURD) 1382 modify_u32(argv[0], "Translator Block", 1383 decimal_format, &inode.osd1.hurd1.h_i_translator); 1384 1385 modify_u32(argv[0], "Fragment address", decimal_format, &inode.i_faddr); 1386 switch (os) { 1387 case EXT2_OS_HURD: 1388 frag = &inode.osd2.hurd2.h_i_frag; 1389 fsize = &inode.osd2.hurd2.h_i_fsize; 1390 break; 1391 default: 1392 frag = fsize = 0; 1393 } 1394 if (frag) 1395 modify_u8(argv[0], "Fragment number", decimal_format, frag); 1396 if (fsize) 1397 modify_u8(argv[0], "Fragment size", decimal_format, fsize); 1398 1399 for (i=0; i < EXT2_NDIR_BLOCKS; i++) { 1400 sprintf(buf, "Direct Block #%d", i); 1401 modify_u32(argv[0], buf, decimal_format, &inode.i_block[i]); 1402 } 1403 modify_u32(argv[0], "Indirect Block", decimal_format, 1404 &inode.i_block[EXT2_IND_BLOCK]); 1405 modify_u32(argv[0], "Double Indirect Block", decimal_format, 1406 &inode.i_block[EXT2_DIND_BLOCK]); 1407 modify_u32(argv[0], "Triple Indirect Block", decimal_format, 1408 &inode.i_block[EXT2_TIND_BLOCK]); 1409 if (debugfs_write_inode(inode_num, &inode, argv[1])) 1410 return; 1411 } 1412 #endif /* READ_ONLY */ 1413 1414 void do_change_working_dir(int argc, char *argv[], 1415 int sci_idx EXT2FS_ATTR((unused)), 1416 void *infop EXT2FS_ATTR((unused))) 1417 { 1418 ext2_ino_t inode; 1419 int retval; 1420 1421 if (common_inode_args_process(argc, argv, &inode, 0)) 1422 return; 1423 1424 retval = ext2fs_check_directory(current_fs, inode); 1425 if (retval) { 1426 com_err(argv[1], retval, 0); 1427 return; 1428 } 1429 cwd = inode; 1430 return; 1431 } 1432 1433 void do_print_working_directory(int argc, char *argv[], 1434 int sci_idx EXT2FS_ATTR((unused)), 1435 void *infop EXT2FS_ATTR((unused))) 1436 { 1437 int retval; 1438 char *pathname = NULL; 1439 1440 if (common_args_process(argc, argv, 1, 1, 1441 "print_working_directory", "", 0)) 1442 return; 1443 1444 retval = ext2fs_get_pathname(current_fs, cwd, 0, &pathname); 1445 if (retval) { 1446 com_err(argv[0], retval, 1447 "while trying to get pathname of cwd"); 1448 } 1449 printf("[pwd] INODE: %6u PATH: %s\n", 1450 cwd, pathname ? pathname : "NULL"); 1451 if (pathname) { 1452 free(pathname); 1453 pathname = NULL; 1454 } 1455 retval = ext2fs_get_pathname(current_fs, root, 0, &pathname); 1456 if (retval) { 1457 com_err(argv[0], retval, 1458 "while trying to get pathname of root"); 1459 } 1460 printf("[root] INODE: %6u PATH: %s\n", 1461 root, pathname ? pathname : "NULL"); 1462 if (pathname) { 1463 free(pathname); 1464 pathname = NULL; 1465 } 1466 return; 1467 } 1468 1469 #ifndef READ_ONLY 1470 static void make_link(char *sourcename, char *destname) 1471 { 1472 ext2_ino_t ino; 1473 struct ext2_inode inode; 1474 int retval; 1475 ext2_ino_t dir; 1476 char *dest, *cp, *base_name; 1477 1478 /* 1479 * Get the source inode 1480 */ 1481 ino = string_to_inode(sourcename); 1482 if (!ino) 1483 return; 1484 base_name = strrchr(sourcename, '/'); 1485 if (base_name) 1486 base_name++; 1487 else 1488 base_name = sourcename; 1489 /* 1490 * Figure out the destination. First see if it exists and is 1491 * a directory. 1492 */ 1493 if (! (retval=ext2fs_namei(current_fs, root, cwd, destname, &dir))) 1494 dest = base_name; 1495 else { 1496 /* 1497 * OK, it doesn't exist. See if it is 1498 * '<dir>/basename' or 'basename' 1499 */ 1500 cp = strrchr(destname, '/'); 1501 if (cp) { 1502 *cp = 0; 1503 dir = string_to_inode(destname); 1504 if (!dir) 1505 return; 1506 dest = cp+1; 1507 } else { 1508 dir = cwd; 1509 dest = destname; 1510 } 1511 } 1512 1513 if (debugfs_read_inode(ino, &inode, sourcename)) 1514 return; 1515 1516 retval = ext2fs_link(current_fs, dir, dest, ino, 1517 ext2_file_type(inode.i_mode)); 1518 if (retval) 1519 com_err("make_link", retval, 0); 1520 return; 1521 } 1522 1523 1524 void do_link(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1525 void *infop EXT2FS_ATTR((unused))) 1526 { 1527 if (common_args_process(argc, argv, 3, 3, "link", 1528 "<source file> <dest_name>", CHECK_FS_RW)) 1529 return; 1530 1531 make_link(argv[1], argv[2]); 1532 } 1533 1534 static int mark_blocks_proc(ext2_filsys fs, blk64_t *blocknr, 1535 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 1536 blk64_t ref_block EXT2FS_ATTR((unused)), 1537 int ref_offset EXT2FS_ATTR((unused)), 1538 void *private EXT2FS_ATTR((unused))) 1539 { 1540 blk64_t block; 1541 1542 block = *blocknr; 1543 ext2fs_block_alloc_stats2(fs, block, +1); 1544 return 0; 1545 } 1546 1547 void do_undel(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1548 void *infop EXT2FS_ATTR((unused))) 1549 { 1550 ext2_ino_t ino; 1551 struct ext2_inode inode; 1552 1553 if (common_args_process(argc, argv, 2, 3, "undelete", 1554 "<inode_num> [dest_name]", 1555 CHECK_FS_RW | CHECK_FS_BITMAPS)) 1556 return; 1557 1558 ino = string_to_inode(argv[1]); 1559 if (!ino) 1560 return; 1561 1562 if (debugfs_read_inode(ino, &inode, argv[1])) 1563 return; 1564 1565 if (ext2fs_test_inode_bitmap2(current_fs->inode_map, ino)) { 1566 com_err(argv[1], 0, "Inode is not marked as deleted"); 1567 return; 1568 } 1569 1570 /* 1571 * XXX this function doesn't handle changing the links count on the 1572 * parent directory when undeleting a directory. 1573 */ 1574 inode.i_links_count = LINUX_S_ISDIR(inode.i_mode) ? 2 : 1; 1575 inode.i_dtime = 0; 1576 1577 if (debugfs_write_inode(ino, &inode, argv[0])) 1578 return; 1579 1580 ext2fs_block_iterate3(current_fs, ino, BLOCK_FLAG_READ_ONLY, NULL, 1581 mark_blocks_proc, NULL); 1582 1583 ext2fs_inode_alloc_stats2(current_fs, ino, +1, 0); 1584 1585 if (argc > 2) 1586 make_link(argv[1], argv[2]); 1587 } 1588 1589 static void unlink_file_by_name(char *filename) 1590 { 1591 int retval; 1592 ext2_ino_t dir; 1593 char *base_name; 1594 1595 base_name = strrchr(filename, '/'); 1596 if (base_name) { 1597 *base_name++ = '\0'; 1598 dir = string_to_inode(filename); 1599 if (!dir) 1600 return; 1601 } else { 1602 dir = cwd; 1603 base_name = filename; 1604 } 1605 retval = ext2fs_unlink(current_fs, dir, base_name, 0, 0); 1606 if (retval) 1607 com_err("unlink_file_by_name", retval, 0); 1608 return; 1609 } 1610 1611 void do_unlink(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1612 void *infop EXT2FS_ATTR((unused))) 1613 { 1614 if (common_args_process(argc, argv, 2, 2, "link", 1615 "<pathname>", CHECK_FS_RW)) 1616 return; 1617 1618 unlink_file_by_name(argv[1]); 1619 } 1620 1621 void do_copy_inode(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1622 void *infop EXT2FS_ATTR((unused))) 1623 { 1624 ext2_ino_t src_ino, dest_ino; 1625 unsigned char buf[4096]; 1626 1627 if (common_args_process(argc, argv, 3, 3, "copy_inode", 1628 "<source file> <dest_name>", CHECK_FS_RW)) 1629 return; 1630 1631 src_ino = string_to_inode(argv[1]); 1632 if (!src_ino) 1633 return; 1634 1635 dest_ino = string_to_inode(argv[2]); 1636 if (!dest_ino) 1637 return; 1638 1639 if (debugfs_read_inode_full(src_ino, (struct ext2_inode *) buf, 1640 argv[0], sizeof(buf))) 1641 return; 1642 1643 if (debugfs_write_inode_full(dest_ino, (struct ext2_inode *) buf, 1644 argv[0], sizeof(buf))) 1645 return; 1646 } 1647 1648 #endif /* READ_ONLY */ 1649 1650 void do_find_free_block(int argc, char *argv[], 1651 int sci_idx EXT2FS_ATTR((unused)), 1652 void *infop EXT2FS_ATTR((unused))) 1653 { 1654 blk64_t free_blk, goal, first_free = 0; 1655 int count; 1656 errcode_t retval; 1657 char *tmp; 1658 1659 if ((argc > 3) || (argc==2 && *argv[1] == '?')) { 1660 com_err(argv[0], 0, "Usage: find_free_block [count [goal]]"); 1661 return; 1662 } 1663 if (check_fs_open(argv[0])) 1664 return; 1665 1666 if (argc > 1) { 1667 count = strtol(argv[1],&tmp,0); 1668 if (*tmp) { 1669 com_err(argv[0], 0, "Bad count - %s", argv[1]); 1670 return; 1671 } 1672 } else 1673 count = 1; 1674 1675 if (argc > 2) { 1676 goal = strtol(argv[2], &tmp, 0); 1677 if (*tmp) { 1678 com_err(argv[0], 0, "Bad goal - %s", argv[1]); 1679 return; 1680 } 1681 } 1682 else 1683 goal = current_fs->super->s_first_data_block; 1684 1685 printf("Free blocks found: "); 1686 free_blk = goal - 1; 1687 while (count-- > 0) { 1688 retval = ext2fs_new_block2(current_fs, free_blk + 1, 0, 1689 &free_blk); 1690 if (first_free) { 1691 if (first_free == free_blk) 1692 break; 1693 } else 1694 first_free = free_blk; 1695 if (retval) { 1696 com_err("ext2fs_new_block", retval, 0); 1697 return; 1698 } else 1699 printf("%llu ", free_blk); 1700 } 1701 printf("\n"); 1702 } 1703 1704 void do_find_free_inode(int argc, char *argv[], 1705 int sci_idx EXT2FS_ATTR((unused)), 1706 void *infop EXT2FS_ATTR((unused))) 1707 { 1708 ext2_ino_t free_inode, dir; 1709 int mode; 1710 int retval; 1711 char *tmp; 1712 1713 if (argc > 3 || (argc>1 && *argv[1] == '?')) { 1714 com_err(argv[0], 0, "Usage: find_free_inode [dir [mode]]"); 1715 return; 1716 } 1717 if (check_fs_open(argv[0])) 1718 return; 1719 1720 if (argc > 1) { 1721 dir = strtol(argv[1], &tmp, 0); 1722 if (*tmp) { 1723 com_err(argv[0], 0, "Bad dir - %s", argv[1]); 1724 return; 1725 } 1726 } 1727 else 1728 dir = root; 1729 if (argc > 2) { 1730 mode = strtol(argv[2], &tmp, 0); 1731 if (*tmp) { 1732 com_err(argv[0], 0, "Bad mode - %s", argv[2]); 1733 return; 1734 } 1735 } else 1736 mode = 010755; 1737 1738 retval = ext2fs_new_inode(current_fs, dir, mode, 0, &free_inode); 1739 if (retval) 1740 com_err("ext2fs_new_inode", retval, 0); 1741 else 1742 printf("Free inode found: %u\n", free_inode); 1743 } 1744 1745 #ifndef READ_ONLY 1746 void do_write(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1747 void *infop EXT2FS_ATTR((unused))) 1748 { 1749 errcode_t retval; 1750 1751 if (common_args_process(argc, argv, 3, 3, "write", 1752 "<native file> <new file>", CHECK_FS_RW)) 1753 return; 1754 1755 retval = do_write_internal(current_fs, cwd, argv[1], argv[2], root); 1756 if (retval) 1757 com_err(argv[0], retval, 0); 1758 } 1759 1760 void do_mknod(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1761 void *infop EXT2FS_ATTR((unused))) 1762 { 1763 unsigned long major, minor; 1764 errcode_t retval; 1765 int nr; 1766 struct stat st; 1767 1768 if (check_fs_open(argv[0])) 1769 return; 1770 if (argc < 3 || argv[2][1]) { 1771 usage: 1772 com_err(argv[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]"); 1773 return; 1774 } 1775 1776 minor = major = 0; 1777 switch (argv[2][0]) { 1778 case 'p': 1779 st.st_mode = S_IFIFO; 1780 nr = 3; 1781 break; 1782 case 'c': 1783 st.st_mode = S_IFCHR; 1784 nr = 5; 1785 break; 1786 case 'b': 1787 st.st_mode = S_IFBLK; 1788 nr = 5; 1789 break; 1790 default: 1791 nr = 0; 1792 } 1793 1794 if (nr == 5) { 1795 major = strtoul(argv[3], argv+3, 0); 1796 minor = strtoul(argv[4], argv+4, 0); 1797 if (major > 65535 || minor > 65535 || argv[3][0] || argv[4][0]) 1798 nr = 0; 1799 } 1800 1801 if (argc != nr) 1802 goto usage; 1803 1804 st.st_rdev = makedev(major, minor); 1805 retval = do_mknod_internal(current_fs, cwd, argv[1], 1806 st.st_mode, st.st_rdev); 1807 if (retval) 1808 com_err(argv[0], retval, 0); 1809 } 1810 1811 void do_mkdir(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1812 void *infop EXT2FS_ATTR((unused))) 1813 { 1814 errcode_t retval; 1815 1816 if (common_args_process(argc, argv, 2, 2, "mkdir", 1817 "<filename>", CHECK_FS_RW)) 1818 return; 1819 1820 retval = do_mkdir_internal(current_fs, cwd, argv[1], root); 1821 if (retval) 1822 com_err(argv[0], retval, 0); 1823 1824 } 1825 1826 static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr, 1827 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 1828 blk64_t ref_block EXT2FS_ATTR((unused)), 1829 int ref_offset EXT2FS_ATTR((unused)), 1830 void *private) 1831 { 1832 blk64_t block = *blocknr; 1833 blk64_t *last_cluster = (blk64_t *)private; 1834 blk64_t cluster = EXT2FS_B2C(fs, block); 1835 1836 if (cluster == *last_cluster) 1837 return 0; 1838 1839 *last_cluster = cluster; 1840 1841 ext2fs_block_alloc_stats2(fs, block, -1); 1842 return 0; 1843 } 1844 1845 static void kill_file_by_inode(ext2_ino_t inode) 1846 { 1847 struct ext2_inode inode_buf; 1848 1849 if (debugfs_read_inode(inode, &inode_buf, 0)) 1850 return; 1851 inode_buf.i_dtime = current_fs->now ? current_fs->now : time(0); 1852 if (debugfs_write_inode(inode, &inode_buf, 0)) 1853 return; 1854 if (ext2fs_inode_has_valid_blocks2(current_fs, &inode_buf)) { 1855 blk64_t last_cluster = 0; 1856 ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, 1857 NULL, release_blocks_proc, &last_cluster); 1858 } 1859 printf("\n"); 1860 ext2fs_inode_alloc_stats2(current_fs, inode, -1, 1861 LINUX_S_ISDIR(inode_buf.i_mode)); 1862 } 1863 1864 1865 void do_kill_file(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1866 void *infop EXT2FS_ATTR((unused))) 1867 { 1868 ext2_ino_t inode_num; 1869 1870 if (common_inode_args_process(argc, argv, &inode_num, CHECK_FS_RW)) 1871 return; 1872 1873 kill_file_by_inode(inode_num); 1874 } 1875 1876 void do_rm(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1877 void *infop EXT2FS_ATTR((unused))) 1878 { 1879 int retval; 1880 ext2_ino_t inode_num; 1881 struct ext2_inode inode; 1882 1883 if (common_args_process(argc, argv, 2, 2, "rm", 1884 "<filename>", CHECK_FS_RW)) 1885 return; 1886 1887 retval = ext2fs_namei(current_fs, root, cwd, argv[1], &inode_num); 1888 if (retval) { 1889 com_err(argv[0], retval, "while trying to resolve filename"); 1890 return; 1891 } 1892 1893 if (debugfs_read_inode(inode_num, &inode, argv[0])) 1894 return; 1895 1896 if (LINUX_S_ISDIR(inode.i_mode)) { 1897 com_err(argv[0], 0, "file is a directory"); 1898 return; 1899 } 1900 1901 --inode.i_links_count; 1902 if (debugfs_write_inode(inode_num, &inode, argv[0])) 1903 return; 1904 1905 unlink_file_by_name(argv[1]); 1906 if (inode.i_links_count == 0) 1907 kill_file_by_inode(inode_num); 1908 } 1909 1910 struct rd_struct { 1911 ext2_ino_t parent; 1912 int empty; 1913 }; 1914 1915 static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), 1916 int entry EXT2FS_ATTR((unused)), 1917 struct ext2_dir_entry *dirent, 1918 int offset EXT2FS_ATTR((unused)), 1919 int blocksize EXT2FS_ATTR((unused)), 1920 char *buf EXT2FS_ATTR((unused)), 1921 void *private) 1922 { 1923 struct rd_struct *rds = (struct rd_struct *) private; 1924 1925 if (dirent->inode == 0) 1926 return 0; 1927 if ((ext2fs_dirent_name_len(dirent) == 1) && (dirent->name[0] == '.')) 1928 return 0; 1929 if ((ext2fs_dirent_name_len(dirent) == 2) && (dirent->name[0] == '.') && 1930 (dirent->name[1] == '.')) { 1931 rds->parent = dirent->inode; 1932 return 0; 1933 } 1934 rds->empty = 0; 1935 return 0; 1936 } 1937 1938 void do_rmdir(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 1939 void *infop EXT2FS_ATTR((unused))) 1940 { 1941 int retval; 1942 ext2_ino_t inode_num; 1943 struct ext2_inode inode; 1944 struct rd_struct rds; 1945 1946 if (common_args_process(argc, argv, 2, 2, "rmdir", 1947 "<filename>", CHECK_FS_RW)) 1948 return; 1949 1950 retval = ext2fs_namei(current_fs, root, cwd, argv[1], &inode_num); 1951 if (retval) { 1952 com_err(argv[0], retval, "while trying to resolve filename"); 1953 return; 1954 } 1955 1956 if (debugfs_read_inode(inode_num, &inode, argv[0])) 1957 return; 1958 1959 if (!LINUX_S_ISDIR(inode.i_mode)) { 1960 com_err(argv[0], 0, "file is not a directory"); 1961 return; 1962 } 1963 1964 rds.parent = 0; 1965 rds.empty = 1; 1966 1967 retval = ext2fs_dir_iterate2(current_fs, inode_num, 0, 1968 0, rmdir_proc, &rds); 1969 if (retval) { 1970 com_err(argv[0], retval, "while iterating over directory"); 1971 return; 1972 } 1973 if (rds.empty == 0) { 1974 com_err(argv[0], 0, "directory not empty"); 1975 return; 1976 } 1977 1978 inode.i_links_count = 0; 1979 if (debugfs_write_inode(inode_num, &inode, argv[0])) 1980 return; 1981 1982 unlink_file_by_name(argv[1]); 1983 kill_file_by_inode(inode_num); 1984 1985 if (rds.parent) { 1986 if (debugfs_read_inode(rds.parent, &inode, argv[0])) 1987 return; 1988 if (inode.i_links_count > 1) 1989 inode.i_links_count--; 1990 if (debugfs_write_inode(rds.parent, &inode, argv[0])) 1991 return; 1992 } 1993 } 1994 #endif /* READ_ONLY */ 1995 1996 void do_show_debugfs_params(int argc EXT2FS_ATTR((unused)), 1997 char *argv[] EXT2FS_ATTR((unused)), 1998 int sci_idx EXT2FS_ATTR((unused)), 1999 void *infop EXT2FS_ATTR((unused))) 2000 { 2001 if (current_fs) 2002 printf("Open mode: read-%s\n", 2003 current_fs->flags & EXT2_FLAG_RW ? "write" : "only"); 2004 printf("Filesystem in use: %s\n", 2005 current_fs ? current_fs->device_name : "--none--"); 2006 } 2007 2008 #ifndef READ_ONLY 2009 void do_expand_dir(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 2010 void *infop EXT2FS_ATTR((unused))) 2011 { 2012 ext2_ino_t inode; 2013 int retval; 2014 2015 if (common_inode_args_process(argc, argv, &inode, CHECK_FS_RW)) 2016 return; 2017 2018 retval = ext2fs_expand_dir(current_fs, inode); 2019 if (retval) 2020 com_err("ext2fs_expand_dir", retval, 0); 2021 return; 2022 } 2023 2024 void do_features(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 2025 void *infop EXT2FS_ATTR((unused))) 2026 { 2027 int i; 2028 2029 if (check_fs_open(argv[0])) 2030 return; 2031 2032 if ((argc != 1) && check_fs_read_write(argv[0])) 2033 return; 2034 for (i=1; i < argc; i++) { 2035 if (e2p_edit_feature(argv[i], 2036 ¤t_fs->super->s_feature_compat, 0)) 2037 com_err(argv[0], 0, "Unknown feature: %s\n", 2038 argv[i]); 2039 else 2040 ext2fs_mark_super_dirty(current_fs); 2041 } 2042 print_features(current_fs->super, stdout); 2043 } 2044 #endif /* READ_ONLY */ 2045 2046 void do_bmap(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 2047 void *infop EXT2FS_ATTR((unused))) 2048 { 2049 ext2_ino_t ino; 2050 blk64_t blk, pblk = 0; 2051 int c, err, flags = 0, ret_flags = 0; 2052 errcode_t errcode; 2053 2054 if (check_fs_open(argv[0])) 2055 return; 2056 2057 reset_getopt(); 2058 while ((c = getopt (argc, argv, "a")) != EOF) { 2059 switch (c) { 2060 case 'a': 2061 flags |= BMAP_ALLOC; 2062 break; 2063 default: 2064 goto print_usage; 2065 } 2066 } 2067 2068 if (argc <= optind+1) { 2069 print_usage: 2070 com_err(0, 0, 2071 "Usage: bmap [-a] <file> logical_blk [physical_blk]"); 2072 return; 2073 } 2074 2075 ino = string_to_inode(argv[optind++]); 2076 if (!ino) 2077 return; 2078 err = strtoblk(argv[0], argv[optind++], "logical block", &blk); 2079 if (err) 2080 return; 2081 2082 if (argc > optind+1) 2083 goto print_usage; 2084 2085 if (argc == optind+1) { 2086 err = strtoblk(argv[0], argv[optind++], 2087 "physical block", &pblk); 2088 if (err) 2089 return; 2090 if (flags & BMAP_ALLOC) { 2091 com_err(0, 0, "Can't set and allocate a block"); 2092 return; 2093 } 2094 flags |= BMAP_SET; 2095 } 2096 2097 errcode = ext2fs_bmap2(current_fs, ino, 0, 0, flags, blk, 2098 &ret_flags, &pblk); 2099 if (errcode) { 2100 com_err(argv[0], errcode, 2101 "while mapping logical block %llu\n", blk); 2102 return; 2103 } 2104 printf("%llu", pblk); 2105 if (ret_flags & BMAP_RET_UNINIT) 2106 fputs(" (uninit)", stdout); 2107 fputc('\n', stdout); 2108 } 2109 2110 void do_imap(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 2111 void *infop EXT2FS_ATTR((unused))) 2112 { 2113 ext2_ino_t ino; 2114 unsigned long group, block, block_nr, offset; 2115 2116 if (common_args_process(argc, argv, 2, 2, argv[0], 2117 "<file>", 0)) 2118 return; 2119 ino = string_to_inode(argv[1]); 2120 if (!ino) 2121 return; 2122 2123 group = (ino - 1) / EXT2_INODES_PER_GROUP(current_fs->super); 2124 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(current_fs->super)) * 2125 EXT2_INODE_SIZE(current_fs->super); 2126 block = offset >> EXT2_BLOCK_SIZE_BITS(current_fs->super); 2127 if (!ext2fs_inode_table_loc(current_fs, (unsigned)group)) { 2128 com_err(argv[0], 0, "Inode table for group %lu is missing\n", 2129 group); 2130 return; 2131 } 2132 block_nr = ext2fs_inode_table_loc(current_fs, (unsigned)group) + 2133 block; 2134 offset &= (EXT2_BLOCK_SIZE(current_fs->super) - 1); 2135 2136 printf("Inode %d is part of block group %lu\n" 2137 "\tlocated at block %lu, offset 0x%04lx\n", ino, group, 2138 block_nr, offset); 2139 2140 } 2141 2142 void do_idump(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 2143 void *infop EXT2FS_ATTR((unused))) 2144 { 2145 struct ext2_inode_large *inode; 2146 ext2_ino_t ino; 2147 unsigned char *buf; 2148 errcode_t err; 2149 unsigned int isize, size, offset = 0; 2150 int c, mode = 0; 2151 2152 reset_getopt(); 2153 while ((c = getopt (argc, argv, "bex")) != EOF) { 2154 if (mode || c == '?') { 2155 com_err(argv[0], 0, 2156 "Usage: inode_dump [-b]|[-e] <file>"); 2157 return; 2158 } 2159 mode = c; 2160 } 2161 if (optind != argc-1) 2162 return; 2163 2164 if (check_fs_open(argv[0])) 2165 return; 2166 2167 ino = string_to_inode(argv[optind]); 2168 if (!ino) 2169 return; 2170 2171 isize = EXT2_INODE_SIZE(current_fs->super); 2172 err = ext2fs_get_mem(isize, &buf); 2173 if (err) { 2174 com_err(argv[0], err, "while allocating memory"); 2175 return; 2176 } 2177 2178 err = ext2fs_read_inode_full(current_fs, ino, 2179 (struct ext2_inode *)buf, isize); 2180 if (err) { 2181 com_err(argv[0], err, "while reading inode %u", ino); 2182 goto err; 2183 } 2184 2185 inode = (struct ext2_inode_large *) buf; 2186 size = isize; 2187 switch (mode) { 2188 case 'b': 2189 offset = ((char *) (&inode->i_block)) - ((char *) buf); 2190 size = sizeof(inode->i_block); 2191 break; 2192 case 'x': 2193 case 'e': 2194 if (size <= EXT2_GOOD_OLD_INODE_SIZE) { 2195 com_err(argv[0], 0, "No extra space in inode"); 2196 goto err; 2197 } 2198 offset = EXT2_GOOD_OLD_INODE_SIZE + inode->i_extra_isize; 2199 if (offset > size) 2200 goto err; 2201 size -= offset; 2202 break; 2203 } 2204 if (mode == 'x') 2205 raw_inode_xattr_dump(stdout, buf + offset, size); 2206 else 2207 do_byte_hexdump(stdout, buf + offset, size); 2208 err: 2209 ext2fs_free_mem(&buf); 2210 } 2211 2212 #ifndef READ_ONLY 2213 void do_set_current_time(int argc, char *argv[], 2214 int sci_idx EXT2FS_ATTR((unused)), 2215 void *infop EXT2FS_ATTR((unused))) 2216 { 2217 __s64 now; 2218 2219 if (common_args_process(argc, argv, 2, 2, argv[0], 2220 "<time>", 0)) 2221 return; 2222 2223 now = string_to_time(argv[1]); 2224 if (now == -1) { 2225 com_err(argv[0], 0, "Couldn't parse argument as a time: %s\n", 2226 argv[1]); 2227 return; 2228 2229 } else { 2230 printf("Setting current time to %s\n", time_to_string(now)); 2231 current_fs->now = now; 2232 } 2233 } 2234 #endif /* READ_ONLY */ 2235 2236 static int find_supp_feature(__u32 *supp, int feature_type, char *name) 2237 { 2238 int compat, bit, ret; 2239 unsigned int feature_mask; 2240 2241 if (name) { 2242 if (feature_type == E2P_FS_FEATURE) 2243 ret = e2p_string2feature(name, &compat, &feature_mask); 2244 else 2245 ret = e2p_jrnl_string2feature(name, &compat, 2246 &feature_mask); 2247 if (ret) 2248 return ret; 2249 2250 if (!(supp[compat] & feature_mask)) 2251 return 1; 2252 } else { 2253 for (compat = 0; compat < 3; compat++) { 2254 for (bit = 0, feature_mask = 1; bit < 32; 2255 bit++, feature_mask <<= 1) { 2256 if (supp[compat] & feature_mask) { 2257 if (feature_type == E2P_FS_FEATURE) 2258 fprintf(stdout, " %s", 2259 e2p_feature2string(compat, 2260 feature_mask)); 2261 else 2262 fprintf(stdout, " %s", 2263 e2p_jrnl_feature2string(compat, 2264 feature_mask)); 2265 } 2266 } 2267 } 2268 fprintf(stdout, "\n"); 2269 } 2270 2271 return 0; 2272 } 2273 2274 void do_supported_features(int argc, char *argv[], 2275 int sci_idx EXT2FS_ATTR((unused)), 2276 void *infop EXT2FS_ATTR((unused))) 2277 { 2278 int ret; 2279 __u32 supp[3] = { EXT2_LIB_FEATURE_COMPAT_SUPP, 2280 EXT2_LIB_FEATURE_INCOMPAT_SUPP, 2281 EXT2_LIB_FEATURE_RO_COMPAT_SUPP }; 2282 __u32 jrnl_supp[3] = { JFS_KNOWN_COMPAT_FEATURES, 2283 JFS_KNOWN_INCOMPAT_FEATURES, 2284 JFS_KNOWN_ROCOMPAT_FEATURES }; 2285 2286 if (argc > 1) { 2287 ret = find_supp_feature(supp, E2P_FS_FEATURE, argv[1]); 2288 if (ret) { 2289 ret = find_supp_feature(jrnl_supp, E2P_JOURNAL_FEATURE, 2290 argv[1]); 2291 } 2292 if (ret) 2293 com_err(argv[0], 0, "Unknown feature: %s\n", argv[1]); 2294 else 2295 fprintf(stdout, "Supported feature: %s\n", argv[1]); 2296 } else { 2297 fprintf(stdout, "Supported features:"); 2298 ret = find_supp_feature(supp, E2P_FS_FEATURE, NULL); 2299 ret = find_supp_feature(jrnl_supp, E2P_JOURNAL_FEATURE, NULL); 2300 } 2301 } 2302 2303 #ifndef READ_ONLY 2304 void do_punch(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 2305 void *infop EXT2FS_ATTR((unused))) 2306 { 2307 ext2_ino_t ino; 2308 blk64_t start, end; 2309 int err; 2310 errcode_t errcode; 2311 2312 if (common_args_process(argc, argv, 3, 4, argv[0], 2313 "<file> start_blk [end_blk]", 2314 CHECK_FS_RW | CHECK_FS_BITMAPS)) 2315 return; 2316 2317 ino = string_to_inode(argv[1]); 2318 if (!ino) 2319 return; 2320 err = strtoblk(argv[0], argv[2], "logical block", &start); 2321 if (err) 2322 return; 2323 if (argc == 4) { 2324 err = strtoblk(argv[0], argv[3], "logical block", &end); 2325 if (err) 2326 return; 2327 } else 2328 end = ~0; 2329 2330 errcode = ext2fs_punch(current_fs, ino, 0, 0, start, end); 2331 2332 if (errcode) { 2333 com_err(argv[0], errcode, 2334 "while truncating inode %u from %llu to %llu\n", ino, 2335 (unsigned long long) start, (unsigned long long) end); 2336 return; 2337 } 2338 } 2339 2340 void do_fallocate(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 2341 void *infop EXT2FS_ATTR((unused))) 2342 { 2343 ext2_ino_t ino; 2344 blk64_t start, end; 2345 int err; 2346 errcode_t errcode; 2347 2348 if (common_args_process(argc, argv, 3, 4, argv[0], 2349 "<file> start_blk [end_blk]", 2350 CHECK_FS_RW | CHECK_FS_BITMAPS)) 2351 return; 2352 2353 ino = string_to_inode(argv[1]); 2354 if (!ino) 2355 return; 2356 err = strtoblk(argv[0], argv[2], "logical block", &start); 2357 if (err) 2358 return; 2359 if (argc == 4) { 2360 err = strtoblk(argv[0], argv[3], "logical block", &end); 2361 if (err) 2362 return; 2363 } else 2364 end = ~0; 2365 2366 errcode = ext2fs_fallocate(current_fs, EXT2_FALLOCATE_INIT_BEYOND_EOF, 2367 ino, NULL, ~0ULL, start, end - start + 1); 2368 2369 if (errcode) { 2370 com_err(argv[0], errcode, 2371 "while fallocating inode %u from %llu to %llu\n", ino, 2372 (unsigned long long) start, (unsigned long long) end); 2373 return; 2374 } 2375 } 2376 #endif /* READ_ONLY */ 2377 2378 void do_symlink(int argc, char *argv[], int sci_idx EXT2FS_ATTR((unused)), 2379 void *infop EXT2FS_ATTR((unused))) 2380 { 2381 errcode_t retval; 2382 2383 if (common_args_process(argc, argv, 3, 3, "symlink", 2384 "<filename> <target>", CHECK_FS_RW)) 2385 return; 2386 2387 retval = do_symlink_internal(current_fs, cwd, argv[1], argv[2], root); 2388 if (retval) 2389 com_err(argv[0], retval, 0); 2390 2391 } 2392 2393 #if CONFIG_MMP 2394 void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[], 2395 int sci_idx EXT2FS_ATTR((unused)), 2396 void *infop EXT2FS_ATTR((unused))) 2397 { 2398 struct mmp_struct *mmp_s; 2399 unsigned long long mmp_block; 2400 time_t t; 2401 errcode_t retval = 0; 2402 2403 if (check_fs_open(argv[0])) 2404 return; 2405 2406 if (argc > 1) { 2407 char *end = NULL; 2408 mmp_block = strtoull(argv[1], &end, 0); 2409 if (end == argv[0] || mmp_block == 0) { 2410 fprintf(stderr, "%s: invalid MMP block '%s' given\n", 2411 argv[0], argv[1]); 2412 return; 2413 } 2414 } else { 2415 mmp_block = current_fs->super->s_mmp_block; 2416 } 2417 2418 if (mmp_block == 0) { 2419 fprintf(stderr, "%s: MMP: not active on this filesystem.\n", 2420 argv[0]); 2421 return; 2422 } 2423 2424 if (current_fs->mmp_buf == NULL) { 2425 retval = ext2fs_get_mem(current_fs->blocksize, 2426 ¤t_fs->mmp_buf); 2427 if (retval) { 2428 com_err(argv[0], retval, "allocating MMP buffer.\n"); 2429 return; 2430 } 2431 } 2432 2433 mmp_s = current_fs->mmp_buf; 2434 2435 retval = ext2fs_mmp_read(current_fs, mmp_block, current_fs->mmp_buf); 2436 if (retval) { 2437 com_err(argv[0], retval, "reading MMP block %llu.\n", 2438 mmp_block); 2439 return; 2440 } 2441 2442 t = mmp_s->mmp_time; 2443 fprintf(stdout, "block_number: %llu\n", current_fs->super->s_mmp_block); 2444 fprintf(stdout, "update_interval: %d\n", 2445 current_fs->super->s_mmp_update_interval); 2446 fprintf(stdout, "check_interval: %d\n", mmp_s->mmp_check_interval); 2447 fprintf(stdout, "sequence: %08x\n", mmp_s->mmp_seq); 2448 fprintf(stdout, "time: %lld -- %s", mmp_s->mmp_time, ctime(&t)); 2449 fprintf(stdout, "node_name: %s\n", mmp_s->mmp_nodename); 2450 fprintf(stdout, "device_name: %s\n", mmp_s->mmp_bdevname); 2451 fprintf(stdout, "magic: 0x%x\n", mmp_s->mmp_magic); 2452 fprintf(stdout, "checksum: 0x%08x\n", mmp_s->mmp_checksum); 2453 } 2454 #else 2455 void do_dump_mmp(int argc EXT2FS_ATTR((unused)), 2456 char *argv[] EXT2FS_ATTR((unused)), 2457 int sci_idx EXT2FS_ATTR((unused)), 2458 void *infop EXT2FS_ATTR((unused))) 2459 { 2460 fprintf(stdout, "MMP is unsupported, please recompile with " 2461 "--enable-mmp\n"); 2462 } 2463 #endif 2464 2465 static int source_file(const char *cmd_file, int ss_idx) 2466 { 2467 FILE *f; 2468 char buf[BUFSIZ]; 2469 char *cp; 2470 int exit_status = 0; 2471 int retval; 2472 2473 if (strcmp(cmd_file, "-") == 0) 2474 f = stdin; 2475 else { 2476 f = fopen(cmd_file, "r"); 2477 if (!f) { 2478 perror(cmd_file); 2479 exit(1); 2480 } 2481 } 2482 fflush(stdout); 2483 fflush(stderr); 2484 setbuf(stdout, NULL); 2485 setbuf(stderr, NULL); 2486 while (!feof(f)) { 2487 if (fgets(buf, sizeof(buf), f) == NULL) 2488 break; 2489 cp = strchr(buf, '\n'); 2490 if (cp) 2491 *cp = 0; 2492 cp = strchr(buf, '\r'); 2493 if (cp) 2494 *cp = 0; 2495 printf("debugfs: %s\n", buf); 2496 retval = ss_execute_line(ss_idx, buf); 2497 if (retval) { 2498 ss_perror(ss_idx, retval, buf); 2499 exit_status++; 2500 } 2501 } 2502 if (f != stdin) 2503 fclose(f); 2504 return exit_status; 2505 } 2506 2507 int main(int argc, char **argv) 2508 { 2509 int retval; 2510 const char *usage = 2511 "Usage: %s [-b blocksize] [-s superblock] [-f cmd_file] " 2512 "[-R request] [-d data_source_device] [-i] [-n] [-D] [-V] [" 2513 #ifndef READ_ONLY 2514 "[-w] [-z undo_file] " 2515 #endif 2516 "[-c]] [device]"; 2517 int c; 2518 int open_flags = EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS; 2519 char *request = 0; 2520 int exit_status = 0; 2521 char *cmd_file = 0; 2522 blk64_t superblock = 0; 2523 blk64_t blocksize = 0; 2524 int catastrophic = 0; 2525 char *data_filename = 0; 2526 #ifdef READ_ONLY 2527 const char *opt_string = "nicR:f:b:s:Vd:D"; 2528 #else 2529 const char *opt_string = "niwcR:f:b:s:Vd:Dz:"; 2530 char *undo_file = NULL; 2531 #endif 2532 #ifdef CONFIG_JBD_DEBUG 2533 char *jbd_debug; 2534 #endif 2535 2536 if (debug_prog_name == 0) 2537 #ifdef READ_ONLY 2538 debug_prog_name = "rdebugfs"; 2539 #else 2540 debug_prog_name = "debugfs"; 2541 #endif 2542 add_error_table(&et_ext2_error_table); 2543 fprintf (stderr, "%s %s (%s)\n", debug_prog_name, 2544 E2FSPROGS_VERSION, E2FSPROGS_DATE); 2545 2546 #ifdef CONFIG_JBD_DEBUG 2547 jbd_debug = ss_safe_getenv("DEBUGFS_JBD_DEBUG"); 2548 if (jbd_debug) { 2549 int res = sscanf(jbd_debug, "%d", &journal_enable_debug); 2550 2551 if (res != 1) { 2552 fprintf(stderr, 2553 "DEBUGFS_JBD_DEBUG \"%s\" not an integer\n\n", 2554 jbd_debug); 2555 exit(1); 2556 } 2557 } 2558 #endif 2559 while ((c = getopt (argc, argv, opt_string)) != EOF) { 2560 switch (c) { 2561 case 'R': 2562 request = optarg; 2563 break; 2564 case 'f': 2565 cmd_file = optarg; 2566 break; 2567 case 'd': 2568 data_filename = optarg; 2569 break; 2570 case 'i': 2571 open_flags |= EXT2_FLAG_IMAGE_FILE; 2572 break; 2573 case 'n': 2574 open_flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; 2575 break; 2576 #ifndef READ_ONLY 2577 case 'w': 2578 open_flags |= EXT2_FLAG_RW; 2579 break; 2580 #endif 2581 case 'D': 2582 open_flags |= EXT2_FLAG_DIRECT_IO; 2583 break; 2584 case 'b': 2585 blocksize = parse_ulong(optarg, argv[0], 2586 "block size", 0); 2587 break; 2588 case 's': 2589 retval = strtoblk(argv[0], optarg, 2590 "superblock block number", 2591 &superblock); 2592 if (retval) 2593 return 1; 2594 break; 2595 case 'c': 2596 catastrophic = 1; 2597 break; 2598 case 'V': 2599 /* Print version number and exit */ 2600 fprintf(stderr, "\tUsing %s\n", 2601 error_message(EXT2_ET_BASE)); 2602 exit(0); 2603 case 'z': 2604 undo_file = optarg; 2605 break; 2606 default: 2607 com_err(argv[0], 0, usage, debug_prog_name); 2608 return 1; 2609 } 2610 } 2611 if (optind < argc) 2612 open_filesystem(argv[optind], open_flags, 2613 superblock, blocksize, catastrophic, 2614 data_filename, undo_file); 2615 2616 ss_sci_idx = ss_create_invocation(debug_prog_name, "0.0", (char *) NULL, 2617 &debug_cmds, &retval); 2618 if (retval) { 2619 ss_perror(ss_sci_idx, retval, "creating invocation"); 2620 exit(1); 2621 } 2622 ss_get_readline(ss_sci_idx); 2623 2624 (void) ss_add_request_table(ss_sci_idx, &ss_std_requests, 1, &retval); 2625 if (retval) { 2626 ss_perror(ss_sci_idx, retval, "adding standard requests"); 2627 exit (1); 2628 } 2629 if (extra_cmds) 2630 ss_add_request_table(ss_sci_idx, extra_cmds, 1, &retval); 2631 if (retval) { 2632 ss_perror(ss_sci_idx, retval, "adding extra requests"); 2633 exit (1); 2634 } 2635 if (request) { 2636 retval = 0; 2637 retval = ss_execute_line(ss_sci_idx, request); 2638 if (retval) { 2639 ss_perror(ss_sci_idx, retval, request); 2640 exit_status++; 2641 } 2642 } else if (cmd_file) { 2643 exit_status = source_file(cmd_file, ss_sci_idx); 2644 } else { 2645 ss_listen(ss_sci_idx); 2646 } 2647 2648 ss_delete_invocation(ss_sci_idx); 2649 2650 if (current_fs) 2651 close_filesystem(); 2652 2653 remove_error_table(&et_ext2_error_table); 2654 return exit_status; 2655 } 2656