debugfs.c revision a17e9f304bcce0d30578f91bba7456d84a113423
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 int i; 1670 struct ext3_extent_header *eh; 1671 1672 eh = (struct ext3_extent_header *) &inode.i_block[0]; 1673 eh->eh_depth = 0; 1674 eh->eh_entries = 0; 1675 eh->eh_magic = EXT3_EXT_MAGIC; 1676 i = (sizeof(inode.i_block) - sizeof(*eh)) / 1677 sizeof(struct ext3_extent); 1678 eh->eh_max = ext2fs_cpu_to_le16(i); 1679 inode.i_flags |= EXT4_EXTENTS_FL; 1680 } 1681 if (debugfs_write_new_inode(newfile, &inode, argv[0])) { 1682 close(fd); 1683 return; 1684 } 1685 if (LINUX_S_ISREG(inode.i_mode)) { 1686 retval = copy_file(fd, newfile); 1687 if (retval) 1688 com_err("copy_file", retval, 0); 1689 } 1690 close(fd); 1691} 1692 1693void do_mknod(int argc, char *argv[]) 1694{ 1695 unsigned long mode, major, minor; 1696 ext2_ino_t newfile; 1697 errcode_t retval; 1698 struct ext2_inode inode; 1699 int filetype, nr; 1700 1701 if (check_fs_open(argv[0])) 1702 return; 1703 if (argc < 3 || argv[2][1]) { 1704 usage: 1705 com_err(argv[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]"); 1706 return; 1707 } 1708 mode = minor = major = 0; 1709 switch (argv[2][0]) { 1710 case 'p': 1711 mode = LINUX_S_IFIFO; 1712 filetype = EXT2_FT_FIFO; 1713 nr = 3; 1714 break; 1715 case 'c': 1716 mode = LINUX_S_IFCHR; 1717 filetype = EXT2_FT_CHRDEV; 1718 nr = 5; 1719 break; 1720 case 'b': 1721 mode = LINUX_S_IFBLK; 1722 filetype = EXT2_FT_BLKDEV; 1723 nr = 5; 1724 break; 1725 default: 1726 filetype = 0; 1727 nr = 0; 1728 } 1729 if (nr == 5) { 1730 major = strtoul(argv[3], argv+3, 0); 1731 minor = strtoul(argv[4], argv+4, 0); 1732 if (major > 65535 || minor > 65535 || argv[3][0] || argv[4][0]) 1733 nr = 0; 1734 } 1735 if (argc != nr) 1736 goto usage; 1737 if (check_fs_read_write(argv[0])) 1738 return; 1739 retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile); 1740 if (retval) { 1741 com_err(argv[0], retval, 0); 1742 return; 1743 } 1744 printf("Allocated inode: %u\n", newfile); 1745 retval = ext2fs_link(current_fs, cwd, argv[1], newfile, filetype); 1746 if (retval == EXT2_ET_DIR_NO_SPACE) { 1747 retval = ext2fs_expand_dir(current_fs, cwd); 1748 if (retval) { 1749 com_err(argv[0], retval, "while expanding directory"); 1750 return; 1751 } 1752 retval = ext2fs_link(current_fs, cwd, argv[1], newfile, 1753 filetype); 1754 } 1755 if (retval) { 1756 com_err(argv[1], retval, 0); 1757 return; 1758 } 1759 if (ext2fs_test_inode_bitmap2(current_fs->inode_map,newfile)) 1760 com_err(argv[0], 0, "Warning: inode already set"); 1761 ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0); 1762 memset(&inode, 0, sizeof(inode)); 1763 inode.i_mode = mode; 1764 inode.i_atime = inode.i_ctime = inode.i_mtime = 1765 current_fs->now ? current_fs->now : time(0); 1766 if ((major < 256) && (minor < 256)) { 1767 inode.i_block[0] = major*256+minor; 1768 inode.i_block[1] = 0; 1769 } else { 1770 inode.i_block[0] = 0; 1771 inode.i_block[1] = (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); 1772 } 1773 inode.i_links_count = 1; 1774 if (debugfs_write_new_inode(newfile, &inode, argv[0])) 1775 return; 1776} 1777 1778void do_mkdir(int argc, char *argv[]) 1779{ 1780 char *cp; 1781 ext2_ino_t parent; 1782 char *name; 1783 errcode_t retval; 1784 1785 if (common_args_process(argc, argv, 2, 2, "mkdir", 1786 "<filename>", CHECK_FS_RW)) 1787 return; 1788 1789 cp = strrchr(argv[1], '/'); 1790 if (cp) { 1791 *cp = 0; 1792 parent = string_to_inode(argv[1]); 1793 if (!parent) { 1794 com_err(argv[1], ENOENT, 0); 1795 return; 1796 } 1797 name = cp+1; 1798 } else { 1799 parent = cwd; 1800 name = argv[1]; 1801 } 1802 1803try_again: 1804 retval = ext2fs_mkdir(current_fs, parent, 0, name); 1805 if (retval == EXT2_ET_DIR_NO_SPACE) { 1806 retval = ext2fs_expand_dir(current_fs, parent); 1807 if (retval) { 1808 com_err(argv[0], retval, "while expanding directory"); 1809 return; 1810 } 1811 goto try_again; 1812 } 1813 if (retval) { 1814 com_err("ext2fs_mkdir", retval, 0); 1815 return; 1816 } 1817 1818} 1819 1820static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr, 1821 e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), 1822 blk64_t ref_block EXT2FS_ATTR((unused)), 1823 int ref_offset EXT2FS_ATTR((unused)), 1824 void *private EXT2FS_ATTR((unused))) 1825{ 1826 blk64_t block; 1827 1828 block = *blocknr; 1829 ext2fs_block_alloc_stats2(fs, block, -1); 1830 return 0; 1831} 1832 1833static void kill_file_by_inode(ext2_ino_t inode) 1834{ 1835 struct ext2_inode inode_buf; 1836 1837 if (debugfs_read_inode(inode, &inode_buf, 0)) 1838 return; 1839 inode_buf.i_dtime = current_fs->now ? current_fs->now : time(0); 1840 if (debugfs_write_inode(inode, &inode_buf, 0)) 1841 return; 1842 if (!ext2fs_inode_has_valid_blocks2(current_fs, &inode_buf)) 1843 return; 1844 1845 ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL, 1846 release_blocks_proc, NULL); 1847 printf("\n"); 1848 ext2fs_inode_alloc_stats2(current_fs, inode, -1, 1849 LINUX_S_ISDIR(inode_buf.i_mode)); 1850} 1851 1852 1853void do_kill_file(int argc, char *argv[]) 1854{ 1855 ext2_ino_t inode_num; 1856 1857 if (common_inode_args_process(argc, argv, &inode_num, CHECK_FS_RW)) 1858 return; 1859 1860 kill_file_by_inode(inode_num); 1861} 1862 1863void do_rm(int argc, char *argv[]) 1864{ 1865 int retval; 1866 ext2_ino_t inode_num; 1867 struct ext2_inode inode; 1868 1869 if (common_args_process(argc, argv, 2, 2, "rm", 1870 "<filename>", CHECK_FS_RW)) 1871 return; 1872 1873 retval = ext2fs_namei(current_fs, root, cwd, argv[1], &inode_num); 1874 if (retval) { 1875 com_err(argv[0], retval, "while trying to resolve filename"); 1876 return; 1877 } 1878 1879 if (debugfs_read_inode(inode_num, &inode, argv[0])) 1880 return; 1881 1882 if (LINUX_S_ISDIR(inode.i_mode)) { 1883 com_err(argv[0], 0, "file is a directory"); 1884 return; 1885 } 1886 1887 --inode.i_links_count; 1888 if (debugfs_write_inode(inode_num, &inode, argv[0])) 1889 return; 1890 1891 unlink_file_by_name(argv[1]); 1892 if (inode.i_links_count == 0) 1893 kill_file_by_inode(inode_num); 1894} 1895 1896struct rd_struct { 1897 ext2_ino_t parent; 1898 int empty; 1899}; 1900 1901static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), 1902 int entry EXT2FS_ATTR((unused)), 1903 struct ext2_dir_entry *dirent, 1904 int offset EXT2FS_ATTR((unused)), 1905 int blocksize EXT2FS_ATTR((unused)), 1906 char *buf EXT2FS_ATTR((unused)), 1907 void *private) 1908{ 1909 struct rd_struct *rds = (struct rd_struct *) private; 1910 1911 if (dirent->inode == 0) 1912 return 0; 1913 if (((dirent->name_len&0xFF) == 1) && (dirent->name[0] == '.')) 1914 return 0; 1915 if (((dirent->name_len&0xFF) == 2) && (dirent->name[0] == '.') && 1916 (dirent->name[1] == '.')) { 1917 rds->parent = dirent->inode; 1918 return 0; 1919 } 1920 rds->empty = 0; 1921 return 0; 1922} 1923 1924void do_rmdir(int argc, char *argv[]) 1925{ 1926 int retval; 1927 ext2_ino_t inode_num; 1928 struct ext2_inode inode; 1929 struct rd_struct rds; 1930 1931 if (common_args_process(argc, argv, 2, 2, "rmdir", 1932 "<filename>", CHECK_FS_RW)) 1933 return; 1934 1935 retval = ext2fs_namei(current_fs, root, cwd, argv[1], &inode_num); 1936 if (retval) { 1937 com_err(argv[0], retval, "while trying to resolve filename"); 1938 return; 1939 } 1940 1941 if (debugfs_read_inode(inode_num, &inode, argv[0])) 1942 return; 1943 1944 if (!LINUX_S_ISDIR(inode.i_mode)) { 1945 com_err(argv[0], 0, "file is not a directory"); 1946 return; 1947 } 1948 1949 rds.parent = 0; 1950 rds.empty = 1; 1951 1952 retval = ext2fs_dir_iterate2(current_fs, inode_num, 0, 1953 0, rmdir_proc, &rds); 1954 if (retval) { 1955 com_err(argv[0], retval, "while iterating over directory"); 1956 return; 1957 } 1958 if (rds.empty == 0) { 1959 com_err(argv[0], 0, "directory not empty"); 1960 return; 1961 } 1962 1963 inode.i_links_count = 0; 1964 if (debugfs_write_inode(inode_num, &inode, argv[0])) 1965 return; 1966 1967 unlink_file_by_name(argv[1]); 1968 kill_file_by_inode(inode_num); 1969 1970 if (rds.parent) { 1971 if (debugfs_read_inode(rds.parent, &inode, argv[0])) 1972 return; 1973 if (inode.i_links_count > 1) 1974 inode.i_links_count--; 1975 if (debugfs_write_inode(rds.parent, &inode, argv[0])) 1976 return; 1977 } 1978} 1979#endif /* READ_ONLY */ 1980 1981void do_show_debugfs_params(int argc EXT2FS_ATTR((unused)), 1982 char *argv[] EXT2FS_ATTR((unused))) 1983{ 1984 if (current_fs) 1985 printf("Open mode: read-%s\n", 1986 current_fs->flags & EXT2_FLAG_RW ? "write" : "only"); 1987 printf("Filesystem in use: %s\n", 1988 current_fs ? current_fs->device_name : "--none--"); 1989} 1990 1991#ifndef READ_ONLY 1992void do_expand_dir(int argc, char *argv[]) 1993{ 1994 ext2_ino_t inode; 1995 int retval; 1996 1997 if (common_inode_args_process(argc, argv, &inode, CHECK_FS_RW)) 1998 return; 1999 2000 retval = ext2fs_expand_dir(current_fs, inode); 2001 if (retval) 2002 com_err("ext2fs_expand_dir", retval, 0); 2003 return; 2004} 2005 2006void do_features(int argc, char *argv[]) 2007{ 2008 int i; 2009 2010 if (check_fs_open(argv[0])) 2011 return; 2012 2013 if ((argc != 1) && check_fs_read_write(argv[0])) 2014 return; 2015 for (i=1; i < argc; i++) { 2016 if (e2p_edit_feature(argv[i], 2017 ¤t_fs->super->s_feature_compat, 0)) 2018 com_err(argv[0], 0, "Unknown feature: %s\n", 2019 argv[i]); 2020 else 2021 ext2fs_mark_super_dirty(current_fs); 2022 } 2023 print_features(current_fs->super, stdout); 2024} 2025#endif /* READ_ONLY */ 2026 2027void do_bmap(int argc, char *argv[]) 2028{ 2029 ext2_ino_t ino; 2030 blk64_t blk, pblk; 2031 int err; 2032 errcode_t errcode; 2033 2034 if (common_args_process(argc, argv, 3, 3, argv[0], 2035 "<file> logical_blk", 0)) 2036 return; 2037 2038 ino = string_to_inode(argv[1]); 2039 if (!ino) 2040 return; 2041 blk = parse_ulong(argv[2], argv[0], "logical_block", &err); 2042 2043 errcode = ext2fs_bmap2(current_fs, ino, 0, 0, 0, blk, 0, &pblk); 2044 if (errcode) { 2045 com_err("argv[0]", errcode, 2046 "while mapping logical block %llu\n", blk); 2047 return; 2048 } 2049 printf("%llu\n", pblk); 2050} 2051 2052void do_imap(int argc, char *argv[]) 2053{ 2054 ext2_ino_t ino; 2055 unsigned long group, block, block_nr, offset; 2056 2057 if (common_args_process(argc, argv, 2, 2, argv[0], 2058 "<file>", 0)) 2059 return; 2060 ino = string_to_inode(argv[1]); 2061 if (!ino) 2062 return; 2063 2064 group = (ino - 1) / EXT2_INODES_PER_GROUP(current_fs->super); 2065 offset = ((ino - 1) % EXT2_INODES_PER_GROUP(current_fs->super)) * 2066 EXT2_INODE_SIZE(current_fs->super); 2067 block = offset >> EXT2_BLOCK_SIZE_BITS(current_fs->super); 2068 if (!ext2fs_inode_table_loc(current_fs, (unsigned)group)) { 2069 com_err(argv[0], 0, "Inode table for group %lu is missing\n", 2070 group); 2071 return; 2072 } 2073 block_nr = ext2fs_inode_table_loc(current_fs, (unsigned)group) + 2074 block; 2075 offset &= (EXT2_BLOCK_SIZE(current_fs->super) - 1); 2076 2077 printf("Inode %d is part of block group %lu\n" 2078 "\tlocated at block %lu, offset 0x%04lx\n", ino, group, 2079 block_nr, offset); 2080 2081} 2082 2083#ifndef READ_ONLY 2084void do_set_current_time(int argc, char *argv[]) 2085{ 2086 time_t now; 2087 2088 if (common_args_process(argc, argv, 2, 2, argv[0], 2089 "<time>", 0)) 2090 return; 2091 2092 now = string_to_time(argv[1]); 2093 if (now == ((time_t) -1)) { 2094 com_err(argv[0], 0, "Couldn't parse argument as a time: %s\n", 2095 argv[1]); 2096 return; 2097 2098 } else { 2099 printf("Setting current time to %s\n", time_to_string(now)); 2100 current_fs->now = now; 2101 } 2102} 2103#endif /* READ_ONLY */ 2104 2105static int find_supp_feature(__u32 *supp, int feature_type, char *name) 2106{ 2107 int compat, bit, ret; 2108 unsigned int feature_mask; 2109 2110 if (name) { 2111 if (feature_type == E2P_FS_FEATURE) 2112 ret = e2p_string2feature(name, &compat, &feature_mask); 2113 else 2114 ret = e2p_jrnl_string2feature(name, &compat, 2115 &feature_mask); 2116 if (ret) 2117 return ret; 2118 2119 if (!(supp[compat] & feature_mask)) 2120 return 1; 2121 } else { 2122 for (compat = 0; compat < 3; compat++) { 2123 for (bit = 0, feature_mask = 1; bit < 32; 2124 bit++, feature_mask <<= 1) { 2125 if (supp[compat] & feature_mask) { 2126 if (feature_type == E2P_FS_FEATURE) 2127 fprintf(stdout, " %s", 2128 e2p_feature2string(compat, 2129 feature_mask)); 2130 else 2131 fprintf(stdout, " %s", 2132 e2p_jrnl_feature2string(compat, 2133 feature_mask)); 2134 } 2135 } 2136 } 2137 fprintf(stdout, "\n"); 2138 } 2139 2140 return 0; 2141} 2142 2143void do_supported_features(int argc, char *argv[]) 2144{ 2145 int ret; 2146 __u32 supp[3] = { EXT2_LIB_FEATURE_COMPAT_SUPP, 2147 EXT2_LIB_FEATURE_INCOMPAT_SUPP, 2148 EXT2_LIB_FEATURE_RO_COMPAT_SUPP }; 2149 __u32 jrnl_supp[3] = { JFS_KNOWN_COMPAT_FEATURES, 2150 JFS_KNOWN_INCOMPAT_FEATURES, 2151 JFS_KNOWN_ROCOMPAT_FEATURES }; 2152 2153 if (argc > 1) { 2154 ret = find_supp_feature(supp, E2P_FS_FEATURE, argv[1]); 2155 if (ret) { 2156 ret = find_supp_feature(jrnl_supp, E2P_JOURNAL_FEATURE, 2157 argv[1]); 2158 } 2159 if (ret) 2160 com_err(argv[0], 0, "Unknown feature: %s\n", argv[1]); 2161 else 2162 fprintf(stdout, "Supported feature: %s\n", argv[1]); 2163 } else { 2164 fprintf(stdout, "Supported features:"); 2165 ret = find_supp_feature(supp, E2P_FS_FEATURE, NULL); 2166 ret = find_supp_feature(jrnl_supp, E2P_JOURNAL_FEATURE, NULL); 2167 } 2168} 2169 2170#ifndef READ_ONLY 2171void do_punch(int argc, char *argv[]) 2172{ 2173 ext2_ino_t ino; 2174 blk64_t start, end; 2175 int err; 2176 errcode_t errcode; 2177 2178 if (common_args_process(argc, argv, 3, 4, argv[0], 2179 "<file> start_blk [end_blk]", 2180 CHECK_FS_RW | CHECK_FS_BITMAPS)) 2181 return; 2182 2183 ino = string_to_inode(argv[1]); 2184 if (!ino) 2185 return; 2186 start = parse_ulong(argv[2], argv[0], "logical_block", &err); 2187 if (argc == 4) 2188 end = parse_ulong(argv[3], argv[0], "logical_block", &err); 2189 else 2190 end = ~0; 2191 2192 errcode = ext2fs_punch(current_fs, ino, 0, 0, start, end); 2193 2194 if (errcode) { 2195 com_err(argv[0], errcode, 2196 "while truncating inode %u from %llu to %llu\n", ino, 2197 (unsigned long long) start, (unsigned long long) end); 2198 return; 2199 } 2200} 2201#endif /* READ_ONLY */ 2202 2203void do_symlink(int argc, char *argv[]) 2204{ 2205 char *cp; 2206 ext2_ino_t parent; 2207 char *name, *target; 2208 errcode_t retval; 2209 2210 if (common_args_process(argc, argv, 3, 3, "symlink", 2211 "<filename> <target>", CHECK_FS_RW)) 2212 return; 2213 2214 cp = strrchr(argv[1], '/'); 2215 if (cp) { 2216 *cp = 0; 2217 parent = string_to_inode(argv[1]); 2218 if (!parent) { 2219 com_err(argv[1], ENOENT, 0); 2220 return; 2221 } 2222 name = cp+1; 2223 } else { 2224 parent = cwd; 2225 name = argv[1]; 2226 } 2227 target = argv[2]; 2228 2229try_again: 2230 retval = ext2fs_symlink(current_fs, parent, 0, name, target); 2231 if (retval == EXT2_ET_DIR_NO_SPACE) { 2232 retval = ext2fs_expand_dir(current_fs, parent); 2233 if (retval) { 2234 com_err(argv[0], retval, "while expanding directory"); 2235 return; 2236 } 2237 goto try_again; 2238 } 2239 if (retval) { 2240 com_err("ext2fs_symlink", retval, 0); 2241 return; 2242 } 2243 2244} 2245 2246void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[]) 2247{ 2248 struct ext2_super_block *sb; 2249 struct mmp_struct *mmp_s; 2250 time_t t; 2251 errcode_t retval = 0; 2252 2253 if (check_fs_open(argv[0])) 2254 return; 2255 2256 sb = current_fs->super; 2257 if (sb->s_mmp_block <= sb->s_first_data_block || 2258 sb->s_mmp_block >= ext2fs_blocks_count(sb)) { 2259 com_err(argv[0], EXT2_ET_MMP_BAD_BLOCK, "while dumping it.\n"); 2260 return; 2261 } 2262 2263 if (current_fs->mmp_buf == NULL) { 2264 retval = ext2fs_get_mem(current_fs->blocksize, 2265 ¤t_fs->mmp_buf); 2266 if (retval) { 2267 com_err(argv[0], retval, "allocating MMP buffer.\n"); 2268 return; 2269 } 2270 } 2271 2272 mmp_s = current_fs->mmp_buf; 2273 2274 retval = ext2fs_mmp_read(current_fs, current_fs->super->s_mmp_block, 2275 current_fs->mmp_buf); 2276 if (retval) { 2277 com_err(argv[0], retval, "reading MMP block.\n"); 2278 return; 2279 } 2280 2281 t = mmp_s->mmp_time; 2282 fprintf(stdout, "block_number: %llu\n", current_fs->super->s_mmp_block); 2283 fprintf(stdout, "update_interval: %d\n", 2284 current_fs->super->s_mmp_update_interval); 2285 fprintf(stdout, "check_interval: %d\n", mmp_s->mmp_check_interval); 2286 fprintf(stdout, "sequence: %08x\n", mmp_s->mmp_seq); 2287 fprintf(stdout, "time: %lld -- %s", mmp_s->mmp_time, ctime(&t)); 2288 fprintf(stdout, "node_name: %s\n", mmp_s->mmp_nodename); 2289 fprintf(stdout, "device_name: %s\n", mmp_s->mmp_bdevname); 2290 fprintf(stdout, "magic: 0x%x\n", mmp_s->mmp_magic); 2291} 2292 2293static int source_file(const char *cmd_file, int ss_idx) 2294{ 2295 FILE *f; 2296 char buf[256]; 2297 char *cp; 2298 int exit_status = 0; 2299 int retval; 2300 2301 if (strcmp(cmd_file, "-") == 0) 2302 f = stdin; 2303 else { 2304 f = fopen(cmd_file, "r"); 2305 if (!f) { 2306 perror(cmd_file); 2307 exit(1); 2308 } 2309 } 2310 fflush(stdout); 2311 fflush(stderr); 2312 setbuf(stdout, NULL); 2313 setbuf(stderr, NULL); 2314 while (!feof(f)) { 2315 if (fgets(buf, sizeof(buf), f) == NULL) 2316 break; 2317 cp = strchr(buf, '\n'); 2318 if (cp) 2319 *cp = 0; 2320 cp = strchr(buf, '\r'); 2321 if (cp) 2322 *cp = 0; 2323 printf("debugfs: %s\n", buf); 2324 retval = ss_execute_line(ss_idx, buf); 2325 if (retval) { 2326 ss_perror(ss_idx, retval, buf); 2327 exit_status++; 2328 } 2329 } 2330 if (f != stdin) 2331 fclose(f); 2332 return exit_status; 2333} 2334 2335int main(int argc, char **argv) 2336{ 2337 int retval; 2338 const char *usage = 2339 "Usage: %s [-b blocksize] [-s superblock] [-f cmd_file] " 2340 "[-R request] [-V] [" 2341#ifndef READ_ONLY 2342 "[-w] " 2343#endif 2344 "[-c] device]"; 2345 int c; 2346 int open_flags = EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS; 2347 char *request = 0; 2348 int exit_status = 0; 2349 char *cmd_file = 0; 2350 blk64_t superblock = 0; 2351 blk64_t blocksize = 0; 2352 int catastrophic = 0; 2353 char *data_filename = 0; 2354#ifdef READ_ONLY 2355 const char *opt_string = "icR:f:b:s:Vd:D"; 2356#else 2357 const char *opt_string = "iwcR:f:b:s:Vd:D"; 2358#endif 2359 2360 if (debug_prog_name == 0) 2361#ifdef READ_ONLY 2362 debug_prog_name = "rdebugfs"; 2363#else 2364 debug_prog_name = "debugfs"; 2365#endif 2366 add_error_table(&et_ext2_error_table); 2367 fprintf (stderr, "%s %s (%s)\n", debug_prog_name, 2368 E2FSPROGS_VERSION, E2FSPROGS_DATE); 2369 2370 while ((c = getopt (argc, argv, opt_string)) != EOF) { 2371 switch (c) { 2372 case 'R': 2373 request = optarg; 2374 break; 2375 case 'f': 2376 cmd_file = optarg; 2377 break; 2378 case 'd': 2379 data_filename = optarg; 2380 break; 2381 case 'i': 2382 open_flags |= EXT2_FLAG_IMAGE_FILE; 2383 break; 2384#ifndef READ_ONLY 2385 case 'w': 2386 open_flags |= EXT2_FLAG_RW; 2387 break; 2388#endif 2389 case 'D': 2390 open_flags |= EXT2_FLAG_DIRECT_IO; 2391 break; 2392 case 'b': 2393 blocksize = parse_ulong(optarg, argv[0], 2394 "block size", 0); 2395 break; 2396 case 's': 2397 superblock = parse_ulong(optarg, argv[0], 2398 "superblock number", 0); 2399 break; 2400 case 'c': 2401 catastrophic = 1; 2402 break; 2403 case 'V': 2404 /* Print version number and exit */ 2405 fprintf(stderr, "\tUsing %s\n", 2406 error_message(EXT2_ET_BASE)); 2407 exit(0); 2408 default: 2409 com_err(argv[0], 0, usage, debug_prog_name); 2410 return 1; 2411 } 2412 } 2413 if (optind < argc) 2414 open_filesystem(argv[optind], open_flags, 2415 superblock, blocksize, catastrophic, 2416 data_filename); 2417 2418 sci_idx = ss_create_invocation(debug_prog_name, "0.0", (char *) NULL, 2419 &debug_cmds, &retval); 2420 if (retval) { 2421 ss_perror(sci_idx, retval, "creating invocation"); 2422 exit(1); 2423 } 2424 ss_get_readline(sci_idx); 2425 2426 (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval); 2427 if (retval) { 2428 ss_perror(sci_idx, retval, "adding standard requests"); 2429 exit (1); 2430 } 2431 if (extra_cmds) 2432 ss_add_request_table (sci_idx, extra_cmds, 1, &retval); 2433 if (retval) { 2434 ss_perror(sci_idx, retval, "adding extra requests"); 2435 exit (1); 2436 } 2437 if (request) { 2438 retval = 0; 2439 retval = ss_execute_line(sci_idx, request); 2440 if (retval) { 2441 ss_perror(sci_idx, retval, request); 2442 exit_status++; 2443 } 2444 } else if (cmd_file) { 2445 exit_status = source_file(cmd_file, sci_idx); 2446 } else { 2447 ss_listen(sci_idx); 2448 } 2449 2450 ss_delete_invocation(sci_idx); 2451 2452 if (current_fs) 2453 close_filesystem(); 2454 2455 remove_error_table(&et_ext2_error_table); 2456 return exit_status; 2457} 2458