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