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