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