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