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