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