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