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