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