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