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