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