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