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