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