Home | History | Annotate | Download | only in debugfs
      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 (at) 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
     20 extern int optind;
     21 extern 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 "debugfs.h"
     31 #include "uuid/uuid.h"
     32 #include "e2p/e2p.h"
     33 
     34 #include <ext2fs/ext2_ext_attr.h>
     35 
     36 #include "../version.h"
     37 #include "jfs_user.h"
     38 
     39 #ifndef BUFSIZ
     40 #define BUFSIZ 8192
     41 #endif
     42 
     43 /* 64KiB is the minimium blksize to best minimize system call overhead. */
     44 #ifndef IO_BUFSIZE
     45 #define IO_BUFSIZE 64*1024
     46 #endif
     47 
     48 /* Block size for `st_blocks' */
     49 #ifndef S_BLKSIZE
     50 #define S_BLKSIZE 512
     51 #endif
     52 
     53 ss_request_table *extra_cmds;
     54 const char *debug_prog_name;
     55 int sci_idx;
     56 
     57 ext2_filsys	current_fs = NULL;
     58 ext2_ino_t	root, cwd;
     59 
     60 static void open_filesystem(char *device, int open_flags, blk64_t superblock,
     61 			    blk64_t blocksize, int catastrophic,
     62 			    char *data_filename)
     63 {
     64 	int	retval;
     65 	io_channel data_io = 0;
     66 
     67 	if (superblock != 0 && blocksize == 0) {
     68 		com_err(device, 0, "if you specify the superblock, you must also specify the block size");
     69 		current_fs = NULL;
     70 		return;
     71 	}
     72 
     73 	if (data_filename) {
     74 		if ((open_flags & EXT2_FLAG_IMAGE_FILE) == 0) {
     75 			com_err(device, 0,
     76 				"The -d option is only valid when reading an e2image file");
     77 			current_fs = NULL;
     78 			return;
     79 		}
     80 		retval = unix_io_manager->open(data_filename, 0, &data_io);
     81 		if (retval) {
     82 			com_err(data_filename, 0, "while opening data source");
     83 			current_fs = NULL;
     84 			return;
     85 		}
     86 	}
     87 
     88 	if (catastrophic && (open_flags & EXT2_FLAG_RW)) {
     89 		com_err(device, 0,
     90 			"opening read-only because of catastrophic mode");
     91 		open_flags &= ~EXT2_FLAG_RW;
     92 	}
     93 	if (catastrophic)
     94 		open_flags |= EXT2_FLAG_SKIP_MMP;
     95 
     96 	retval = ext2fs_open(device, open_flags, superblock, blocksize,
     97 			     unix_io_manager, &current_fs);
     98 	if (retval) {
     99 		com_err(device, retval, "while opening filesystem");
    100 		current_fs = NULL;
    101 		return;
    102 	}
    103 	current_fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
    104 
    105 	if (catastrophic)
    106 		com_err(device, 0, "catastrophic mode - not reading inode or group bitmaps");
    107 	else {
    108 		retval = ext2fs_read_inode_bitmap(current_fs);
    109 		if (retval) {
    110 			com_err(device, retval, "while reading inode bitmap");
    111 			goto errout;
    112 		}
    113 		retval = ext2fs_read_block_bitmap(current_fs);
    114 		if (retval) {
    115 			com_err(device, retval, "while reading block bitmap");
    116 			goto errout;
    117 		}
    118 	}
    119 
    120 	if (data_io) {
    121 		retval = ext2fs_set_data_io(current_fs, data_io);
    122 		if (retval) {
    123 			com_err(device, retval,
    124 				"while setting data source");
    125 			goto errout;
    126 		}
    127 	}
    128 
    129 	root = cwd = EXT2_ROOT_INO;
    130 	return;
    131 
    132 errout:
    133 	retval = ext2fs_close(current_fs);
    134 	if (retval)
    135 		com_err(device, retval, "while trying to close filesystem");
    136 	current_fs = NULL;
    137 }
    138 
    139 void do_open_filesys(int argc, char **argv)
    140 {
    141 	int	c, err;
    142 	int	catastrophic = 0;
    143 	blk64_t	superblock = 0;
    144 	blk64_t	blocksize = 0;
    145 	int	open_flags = EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS;
    146 	char	*data_filename = 0;
    147 
    148 	reset_getopt();
    149 	while ((c = getopt (argc, argv, "iwfecb:s:d:D")) != EOF) {
    150 		switch (c) {
    151 		case 'i':
    152 			open_flags |= EXT2_FLAG_IMAGE_FILE;
    153 			break;
    154 		case 'w':
    155 #ifdef READ_ONLY
    156 			goto print_usage;
    157 #else
    158 			open_flags |= EXT2_FLAG_RW;
    159 #endif /* READ_ONLY */
    160 			break;
    161 		case 'f':
    162 			open_flags |= EXT2_FLAG_FORCE;
    163 			break;
    164 		case 'e':
    165 			open_flags |= EXT2_FLAG_EXCLUSIVE;
    166 			break;
    167 		case 'c':
    168 			catastrophic = 1;
    169 			break;
    170 		case 'd':
    171 			data_filename = optarg;
    172 			break;
    173 		case 'D':
    174 			open_flags |= EXT2_FLAG_DIRECT_IO;
    175 			break;
    176 		case 'b':
    177 			blocksize = parse_ulong(optarg, argv[0],
    178 						"block size", &err);
    179 			if (err)
    180 				return;
    181 			break;
    182 		case 's':
    183 			err = strtoblk(argv[0], optarg, &superblock);
    184 			if (err)
    185 				return;
    186 			break;
    187 		default:
    188 			goto print_usage;
    189 		}
    190 	}
    191 	if (optind != argc-1) {
    192 		goto print_usage;
    193 	}
    194 	if (check_fs_not_open(argv[0]))
    195 		return;
    196 	open_filesystem(argv[optind], open_flags,
    197 			superblock, blocksize, catastrophic,
    198 			data_filename);
    199 	return;
    200 
    201 print_usage:
    202 	fprintf(stderr, "%s: Usage: open [-s superblock] [-b blocksize] "
    203 		"[-d image_filename] [-c] [-i] [-f] [-e] [-D] "
    204 #ifndef READ_ONLY
    205 		"[-w] "
    206 #endif
    207 		"<device>\n", argv[0]);
    208 }
    209 
    210 void do_lcd(int argc, char **argv)
    211 {
    212 	if (argc != 2) {
    213 		com_err(argv[0], 0, "Usage: %s %s", argv[0], "<native dir>");
    214 		return;
    215 	}
    216 
    217 	if (chdir(argv[1]) == -1) {
    218 		com_err(argv[0], errno,
    219 			"while trying to change native directory to %s",
    220 			argv[1]);
    221 		return;
    222 	}
    223 }
    224 
    225 static void close_filesystem(NOARGS)
    226 {
    227 	int	retval;
    228 
    229 	if (current_fs->flags & EXT2_FLAG_IB_DIRTY) {
    230 		retval = ext2fs_write_inode_bitmap(current_fs);
    231 		if (retval)
    232 			com_err("ext2fs_write_inode_bitmap", retval, 0);
    233 	}
    234 	if (current_fs->flags & EXT2_FLAG_BB_DIRTY) {
    235 		retval = ext2fs_write_block_bitmap(current_fs);
    236 		if (retval)
    237 			com_err("ext2fs_write_block_bitmap", retval, 0);
    238 	}
    239 	retval = ext2fs_close(current_fs);
    240 	if (retval)
    241 		com_err("ext2fs_close", retval, 0);
    242 	current_fs = NULL;
    243 	return;
    244 }
    245 
    246 void do_close_filesys(int argc, char **argv)
    247 {
    248 	int	c;
    249 
    250 	if (check_fs_open(argv[0]))
    251 		return;
    252 
    253 	reset_getopt();
    254 	while ((c = getopt (argc, argv, "a")) != EOF) {
    255 		switch (c) {
    256 		case 'a':
    257 			current_fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
    258 			break;
    259 		default:
    260 			goto print_usage;
    261 		}
    262 	}
    263 
    264 	if (argc > optind) {
    265 	print_usage:
    266 		com_err(0, 0, "Usage: close_filesys [-a]");
    267 		return;
    268 	}
    269 
    270 	close_filesystem();
    271 }
    272 
    273 #ifndef READ_ONLY
    274 void do_init_filesys(int argc, char **argv)
    275 {
    276 	struct ext2_super_block param;
    277 	errcode_t	retval;
    278 	int		err;
    279 	blk64_t		blocks;
    280 
    281 	if (common_args_process(argc, argv, 3, 3, "initialize",
    282 				"<device> <blocks>", CHECK_FS_NOTOPEN))
    283 		return;
    284 
    285 	memset(&param, 0, sizeof(struct ext2_super_block));
    286 	err = strtoblk(argv[0], argv[2], &blocks);
    287 	if (err)
    288 		return;
    289 	ext2fs_blocks_count_set(&param, blocks);
    290 	if (err)
    291 		return;
    292 	retval = ext2fs_initialize(argv[1], 0, &param,
    293 				   unix_io_manager, &current_fs);
    294 	if (retval) {
    295 		com_err(argv[1], retval, "while initializing filesystem");
    296 		current_fs = NULL;
    297 		return;
    298 	}
    299 	root = cwd = EXT2_ROOT_INO;
    300 	return;
    301 }
    302 
    303 static void print_features(struct ext2_super_block * s, FILE *f)
    304 {
    305 	int	i, j, printed=0;
    306 	__u32	*mask = &s->s_feature_compat, m;
    307 
    308 	fputs("Filesystem features:", f);
    309 	for (i=0; i <3; i++,mask++) {
    310 		for (j=0,m=1; j < 32; j++, m<<=1) {
    311 			if (*mask & m) {
    312 				fprintf(f, " %s", e2p_feature2string(i, m));
    313 				printed++;
    314 			}
    315 		}
    316 	}
    317 	if (printed == 0)
    318 		fputs("(none)", f);
    319 	fputs("\n", f);
    320 }
    321 #endif /* READ_ONLY */
    322 
    323 static void print_bg_opts(ext2_filsys fs, dgrp_t group, int mask,
    324 			  const char *str, int *first, FILE *f)
    325 {
    326 	if (ext2fs_bg_flags_test(fs, group, mask)) {
    327 		if (*first) {
    328 			fputs("           [", f);
    329 			*first = 0;
    330 		} else
    331 			fputs(", ", f);
    332 		fputs(str, f);
    333 	}
    334 }
    335 
    336 void do_show_super_stats(int argc, char *argv[])
    337 {
    338 	const char *units ="block";
    339 	dgrp_t	i;
    340 	FILE 	*out;
    341 	int	c, header_only = 0;
    342 	int	numdirs = 0, first, gdt_csum;
    343 
    344 	reset_getopt();
    345 	while ((c = getopt (argc, argv, "h")) != EOF) {
    346 		switch (c) {
    347 		case 'h':
    348 			header_only++;
    349 			break;
    350 		default:
    351 			goto print_usage;
    352 		}
    353 	}
    354 	if (optind != argc) {
    355 		goto print_usage;
    356 	}
    357 	if (check_fs_open(argv[0]))
    358 		return;
    359 	out = open_pager();
    360 
    361 	if (EXT2_HAS_RO_COMPAT_FEATURE(current_fs->super,
    362 				       EXT4_FEATURE_RO_COMPAT_BIGALLOC))
    363 		units = "cluster";
    364 
    365 	list_super2(current_fs->super, out);
    366 	for (i=0; i < current_fs->group_desc_count; i++)
    367 		numdirs += ext2fs_bg_used_dirs_count(current_fs, i);
    368 	fprintf(out, "Directories:              %d\n", numdirs);
    369 
    370 	if (header_only) {
    371 		close_pager(out);
    372 		return;
    373 	}
    374 
    375 	gdt_csum = EXT2_HAS_RO_COMPAT_FEATURE(current_fs->super,
    376 					      EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
    377 	for (i = 0; i < current_fs->group_desc_count; i++) {
    378 		fprintf(out, " Group %2d: block bitmap at %llu, "
    379 		        "inode bitmap at %llu, "
    380 		        "inode table at %llu\n"
    381 		        "           %u free %s%s, "
    382 		        "%u free %s, "
    383 		        "%u used %s%s",
    384 		        i, ext2fs_block_bitmap_loc(current_fs, i),
    385 		        ext2fs_inode_bitmap_loc(current_fs, i),
    386 			ext2fs_inode_table_loc(current_fs, i),
    387 		        ext2fs_bg_free_blocks_count(current_fs, i), units,
    388 		        ext2fs_bg_free_blocks_count(current_fs, i) != 1 ?
    389 			"s" : "",
    390 		        ext2fs_bg_free_inodes_count(current_fs, i),
    391 		        ext2fs_bg_free_inodes_count(current_fs, i) != 1 ?
    392 			"inodes" : "inode",
    393 		        ext2fs_bg_used_dirs_count(current_fs, i),
    394 		        ext2fs_bg_used_dirs_count(current_fs, i) != 1 ? "directories"
    395  				: "directory", gdt_csum ? ", " : "\n");
    396 		if (gdt_csum)
    397 			fprintf(out, "%u unused %s\n",
    398 				ext2fs_bg_itable_unused(current_fs, i),
    399 				ext2fs_bg_itable_unused(current_fs, i) != 1 ?
    400 				"inodes" : "inode");
    401 		first = 1;
    402 		print_bg_opts(current_fs, i, EXT2_BG_INODE_UNINIT, "Inode not init",
    403 			      &first, out);
    404 		print_bg_opts(current_fs, i, EXT2_BG_BLOCK_UNINIT, "Block not init",
    405 			      &first, out);
    406 		if (gdt_csum) {
    407 			fprintf(out, "%sChecksum 0x%04x",
    408 				first ? "           [":", ", ext2fs_bg_checksum(current_fs, i));
    409 			first = 0;
    410 		}
    411 		if (!first)
    412 			fputs("]\n", out);
    413 	}
    414 	close_pager(out);
    415 	return;
    416 print_usage:
    417 	fprintf(stderr, "%s: Usage: show_super [-h]\n", argv[0]);
    418 }
    419 
    420 #ifndef READ_ONLY
    421 void do_dirty_filesys(int argc EXT2FS_ATTR((unused)),
    422 		      char **argv EXT2FS_ATTR((unused)))
    423 {
    424 	if (check_fs_open(argv[0]))
    425 		return;
    426 	if (check_fs_read_write(argv[0]))
    427 		return;
    428 
    429 	if (argv[1] && !strcmp(argv[1], "-clean"))
    430 		current_fs->super->s_state |= EXT2_VALID_FS;
    431 	else
    432 		current_fs->super->s_state &= ~EXT2_VALID_FS;
    433 	ext2fs_mark_super_dirty(current_fs);
    434 }
    435 #endif /* READ_ONLY */
    436 
    437 struct list_blocks_struct {
    438 	FILE		*f;
    439 	e2_blkcnt_t	total;
    440 	blk64_t		first_block, last_block;
    441 	e2_blkcnt_t	first_bcnt, last_bcnt;
    442 	e2_blkcnt_t	first;
    443 };
    444 
    445 static void finish_range(struct list_blocks_struct *lb)
    446 {
    447 	if (lb->first_block == 0)
    448 		return;
    449 	if (lb->first)
    450 		lb->first = 0;
    451 	else
    452 		fprintf(lb->f, ", ");
    453 	if (lb->first_block == lb->last_block)
    454 		fprintf(lb->f, "(%lld):%llu",
    455 			(long long)lb->first_bcnt, lb->first_block);
    456 	else
    457 		fprintf(lb->f, "(%lld-%lld):%llu-%llu",
    458 			(long long)lb->first_bcnt, (long long)lb->last_bcnt,
    459 			lb->first_block, lb->last_block);
    460 	lb->first_block = 0;
    461 }
    462 
    463 static int list_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)),
    464 			    blk64_t *blocknr, e2_blkcnt_t blockcnt,
    465 			    blk64_t ref_block EXT2FS_ATTR((unused)),
    466 			    int ref_offset EXT2FS_ATTR((unused)),
    467 			    void *private)
    468 {
    469 	struct list_blocks_struct *lb = (struct list_blocks_struct *) private;
    470 
    471 	lb->total++;
    472 	if (blockcnt >= 0) {
    473 		/*
    474 		 * See if we can add on to the existing range (if it exists)
    475 		 */
    476 		if (lb->first_block &&
    477 		    (lb->last_block+1 == *blocknr) &&
    478 		    (lb->last_bcnt+1 == blockcnt)) {
    479 			lb->last_block = *blocknr;
    480 			lb->last_bcnt = blockcnt;
    481 			return 0;
    482 		}
    483 		/*
    484 		 * Start a new range.
    485 		 */
    486 		finish_range(lb);
    487 		lb->first_block = lb->last_block = *blocknr;
    488 		lb->first_bcnt = lb->last_bcnt = blockcnt;
    489 		return 0;
    490 	}
    491 	/*
    492 	 * Not a normal block.  Always force a new range.
    493 	 */
    494 	finish_range(lb);
    495 	if (lb->first)
    496 		lb->first = 0;
    497 	else
    498 		fprintf(lb->f, ", ");
    499 	if (blockcnt == -1)
    500 		fprintf(lb->f, "(IND):%llu", (unsigned long long) *blocknr);
    501 	else if (blockcnt == -2)
    502 		fprintf(lb->f, "(DIND):%llu", (unsigned long long) *blocknr);
    503 	else if (blockcnt == -3)
    504 		fprintf(lb->f, "(TIND):%llu", (unsigned long long) *blocknr);
    505 	return 0;
    506 }
    507 
    508 static void dump_xattr_string(FILE *out, const char *str, int len)
    509 {
    510 	int printable = 0;
    511 	int i;
    512 
    513 	/* check: is string "printable enough?" */
    514 	for (i = 0; i < len; i++)
    515 		if (isprint(str[i]))
    516 			printable++;
    517 
    518 	if (printable <= len*7/8)
    519 		printable = 0;
    520 
    521 	for (i = 0; i < len; i++)
    522 		if (printable)
    523 			fprintf(out, isprint(str[i]) ? "%c" : "\\%03o",
    524 				(unsigned char)str[i]);
    525 		else
    526 			fprintf(out, "%02x ", (unsigned char)str[i]);
    527 }
    528 
    529 static void internal_dump_inode_extra(FILE *out,
    530 				      const char *prefix EXT2FS_ATTR((unused)),
    531 				      ext2_ino_t inode_num EXT2FS_ATTR((unused)),
    532 				      struct ext2_inode_large *inode)
    533 {
    534 	struct ext2_ext_attr_entry *entry;
    535 	__u32 *magic;
    536 	char *start, *end;
    537 	unsigned int storage_size;
    538 
    539 	fprintf(out, "Size of extra inode fields: %u\n", inode->i_extra_isize);
    540 	if (inode->i_extra_isize > EXT2_INODE_SIZE(current_fs->super) -
    541 			EXT2_GOOD_OLD_INODE_SIZE) {
    542 		fprintf(stderr, "invalid inode->i_extra_isize (%u)\n",
    543 				inode->i_extra_isize);
    544 		return;
    545 	}
    546 	storage_size = EXT2_INODE_SIZE(current_fs->super) -
    547 			EXT2_GOOD_OLD_INODE_SIZE -
    548 			inode->i_extra_isize;
    549 	magic = (__u32 *)((char *)inode + EXT2_GOOD_OLD_INODE_SIZE +
    550 			inode->i_extra_isize);
    551 	if (*magic == EXT2_EXT_ATTR_MAGIC) {
    552 		fprintf(out, "Extended attributes stored in inode body: \n");
    553 		end = (char *) inode + EXT2_INODE_SIZE(current_fs->super);
    554 		start = (char *) magic + sizeof(__u32);
    555 		entry = (struct ext2_ext_attr_entry *) start;
    556 		while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
    557 			struct ext2_ext_attr_entry *next =
    558 				EXT2_EXT_ATTR_NEXT(entry);
    559 			if (entry->e_value_size > storage_size ||
    560 					(char *) next >= end) {
    561 				fprintf(out, "invalid EA entry in inode\n");
    562 				return;
    563 			}
    564 			fprintf(out, "  ");
    565 			dump_xattr_string(out, EXT2_EXT_ATTR_NAME(entry),
    566 					  entry->e_name_len);
    567 			fprintf(out, " = \"");
    568 			dump_xattr_string(out, start + entry->e_value_offs,
    569 						entry->e_value_size);
    570 			fprintf(out, "\" (%u)\n", entry->e_value_size);
    571 			entry = next;
    572 		}
    573 	}
    574 }
    575 
    576 static void dump_blocks(FILE *f, const char *prefix, ext2_ino_t inode)
    577 {
    578 	struct list_blocks_struct lb;
    579 
    580 	fprintf(f, "%sBLOCKS:\n%s", prefix, prefix);
    581 	lb.total = 0;
    582 	lb.first_block = 0;
    583 	lb.f = f;
    584 	lb.first = 1;
    585 	ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL,
    586 			      list_blocks_proc, (void *)&lb);
    587 	finish_range(&lb);
    588 	if (lb.total)
    589 		fprintf(f, "\n%sTOTAL: %lld\n", prefix, (long long)lb.total);
    590 	fprintf(f,"\n");
    591 }
    592 
    593 static int int_log10(unsigned long long arg)
    594 {
    595 	int     l = 0;
    596 
    597 	arg = arg / 10;
    598 	while (arg) {
    599 		l++;
    600 		arg = arg / 10;
    601 	}
    602 	return l;
    603 }
    604 
    605 #define DUMP_LEAF_EXTENTS	0x01
    606 #define DUMP_NODE_EXTENTS	0x02
    607 #define DUMP_EXTENT_TABLE	0x04
    608 
    609 static void dump_extents(FILE *f, const char *prefix, ext2_ino_t ino,
    610 			 int flags, int logical_width, int physical_width)
    611 {
    612 	ext2_extent_handle_t	handle;
    613 	struct ext2fs_extent	extent;
    614 	struct ext2_extent_info info;
    615 	int			op = EXT2_EXTENT_ROOT;
    616 	unsigned int		printed = 0;
    617 	errcode_t 		errcode;
    618 
    619 	errcode = ext2fs_extent_open(current_fs, ino, &handle);
    620 	if (errcode)
    621 		return;
    622 
    623 	if (flags & DUMP_EXTENT_TABLE)
    624 		fprintf(f, "Level Entries %*s %*s Length Flags\n",
    625 			(logical_width*2)+3, "Logical",
    626 			(physical_width*2)+3, "Physical");
    627 	else
    628 		fprintf(f, "%sEXTENTS:\n%s", prefix, prefix);
    629 
    630 	while (1) {
    631 		errcode = ext2fs_extent_get(handle, op, &extent);
    632 
    633 		if (errcode)
    634 			break;
    635 
    636 		op = EXT2_EXTENT_NEXT;
    637 
    638 		if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
    639 			continue;
    640 
    641 		if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) {
    642 			if ((flags & DUMP_LEAF_EXTENTS) == 0)
    643 				continue;
    644 		} else {
    645 			if ((flags & DUMP_NODE_EXTENTS) == 0)
    646 				continue;
    647 		}
    648 
    649 		errcode = ext2fs_extent_get_info(handle, &info);
    650 		if (errcode)
    651 			continue;
    652 
    653 		if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
    654 			if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
    655 				continue;
    656 
    657 			if (flags & DUMP_EXTENT_TABLE) {
    658 				fprintf(f, "%2d/%2d %3d/%3d %*llu - %*llu "
    659 					"%*llu%*s %6u\n",
    660 					info.curr_level, info.max_depth,
    661 					info.curr_entry, info.num_entries,
    662 					logical_width,
    663 					extent.e_lblk,
    664 					logical_width,
    665 					extent.e_lblk + (extent.e_len - 1),
    666 					physical_width,
    667 					extent.e_pblk,
    668 					physical_width+3, "", extent.e_len);
    669 				continue;
    670 			}
    671 
    672 			fprintf(f, "%s(ETB%d):%lld",
    673 				printed ? ", " : "", info.curr_level,
    674 				extent.e_pblk);
    675 			printed = 1;
    676 			continue;
    677 		}
    678 
    679 		if (flags & DUMP_EXTENT_TABLE) {
    680 			fprintf(f, "%2d/%2d %3d/%3d %*llu - %*llu "
    681 				"%*llu - %*llu %6u %s\n",
    682 				info.curr_level, info.max_depth,
    683 				info.curr_entry, info.num_entries,
    684 				logical_width,
    685 				extent.e_lblk,
    686 				logical_width,
    687 				extent.e_lblk + (extent.e_len - 1),
    688 				physical_width,
    689 				extent.e_pblk,
    690 				physical_width,
    691 				extent.e_pblk + (extent.e_len - 1),
    692 				extent.e_len,
    693 				extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ?
    694 					"Uninit" : "");
    695 			continue;
    696 		}
    697 
    698 		if (extent.e_len == 0)
    699 			continue;
    700 		else if (extent.e_len == 1)
    701 			fprintf(f,
    702 				"%s(%lld%s):%lld",
    703 				printed ? ", " : "",
    704 				extent.e_lblk,
    705 				extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ?
    706 				"[u]" : "",
    707 				extent.e_pblk);
    708 		else
    709 			fprintf(f,
    710 				"%s(%lld-%lld%s):%lld-%lld",
    711 				printed ? ", " : "",
    712 				extent.e_lblk,
    713 				extent.e_lblk + (extent.e_len - 1),
    714 				extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT ?
    715 					"[u]" : "",
    716 				extent.e_pblk,
    717 				extent.e_pblk + (extent.e_len - 1));
    718 		printed = 1;
    719 	}
    720 	if (printed)
    721 		fprintf(f, "\n");
    722 }
    723 
    724 void internal_dump_inode(FILE *out, const char *prefix,
    725 			 ext2_ino_t inode_num, struct ext2_inode *inode,
    726 			 int do_dump_blocks)
    727 {
    728 	const char *i_type;
    729 	char frag, fsize;
    730 	int os = current_fs->super->s_creator_os;
    731 	struct ext2_inode_large *large_inode;
    732 	int is_large_inode = 0;
    733 
    734 	if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
    735 		is_large_inode = 1;
    736 	large_inode = (struct ext2_inode_large *) inode;
    737 
    738 	if (LINUX_S_ISDIR(inode->i_mode)) i_type = "directory";
    739 	else if (LINUX_S_ISREG(inode->i_mode)) i_type = "regular";
    740 	else if (LINUX_S_ISLNK(inode->i_mode)) i_type = "symlink";
    741 	else if (LINUX_S_ISBLK(inode->i_mode)) i_type = "block special";
    742 	else if (LINUX_S_ISCHR(inode->i_mode)) i_type = "character special";
    743 	else if (LINUX_S_ISFIFO(inode->i_mode)) i_type = "FIFO";
    744 	else if (LINUX_S_ISSOCK(inode->i_mode)) i_type = "socket";
    745 	else i_type = "bad type";
    746 	fprintf(out, "%sInode: %u   Type: %s    ", prefix, inode_num, i_type);
    747 	fprintf(out, "%sMode:  %04o   Flags: 0x%x\n",
    748 		prefix, inode->i_mode & 0777, inode->i_flags);
    749 	if (is_large_inode && large_inode->i_extra_isize >= 24) {
    750 		fprintf(out, "%sGeneration: %u    Version: 0x%08x:%08x\n",
    751 			prefix, inode->i_generation, large_inode->i_version_hi,
    752 			inode->osd1.linux1.l_i_version);
    753 	} else {
    754 		fprintf(out, "%sGeneration: %u    Version: 0x%08x\n", prefix,
    755 			inode->i_generation, inode->osd1.linux1.l_i_version);
    756 	}
    757 	fprintf(out, "%sUser: %5d   Group: %5d   Size: ",
    758 		prefix, inode_uid(*inode), inode_gid(*inode));
    759 	if (LINUX_S_ISREG(inode->i_mode))
    760 		fprintf(out, "%llu\n", EXT2_I_SIZE(inode));
    761 	else
    762 		fprintf(out, "%d\n", inode->i_size);
    763 	if (os == EXT2_OS_HURD)
    764 		fprintf(out,
    765 			"%sFile ACL: %d    Directory ACL: %d Translator: %d\n",
    766 			prefix,
    767 			inode->i_file_acl, LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0,
    768 			inode->osd1.hurd1.h_i_translator);
    769 	else
    770 		fprintf(out, "%sFile ACL: %llu    Directory ACL: %d\n",
    771 			prefix,
    772 			inode->i_file_acl | ((long long)
    773 				(inode->osd2.linux2.l_i_file_acl_high) << 32),
    774 			LINUX_S_ISDIR(inode->i_mode) ? inode->i_dir_acl : 0);
    775 	if (os == EXT2_OS_LINUX)
    776 		fprintf(out, "%sLinks: %d   Blockcount: %llu\n",
    777 			prefix, inode->i_links_count,
    778 			(((unsigned long long)
    779 			  inode->osd2.linux2.l_i_blocks_hi << 32)) +
    780 			inode->i_blocks);
    781 	else
    782 		fprintf(out, "%sLinks: %d   Blockcount: %u\n",
    783 			prefix, inode->i_links_count, inode->i_blocks);
    784 	switch (os) {
    785 	    case EXT2_OS_HURD:
    786 		frag = inode->osd2.hurd2.h_i_frag;
    787 		fsize = inode->osd2.hurd2.h_i_fsize;
    788 		break;
    789 	    default:
    790 		frag = fsize = 0;
    791 	}
    792 	fprintf(out, "%sFragment:  Address: %d    Number: %d    Size: %d\n",
    793 		prefix, inode->i_faddr, frag, fsize);
    794 	if (is_large_inode && large_inode->i_extra_isize >= 24) {
    795 		fprintf(out, "%s ctime: 0x%08x:%08x -- %s", prefix,
    796 			inode->i_ctime, large_inode->i_ctime_extra,
    797 			time_to_string(inode->i_ctime));
    798 		fprintf(out, "%s atime: 0x%08x:%08x -- %s", prefix,
    799 			inode->i_atime, large_inode->i_atime_extra,
    800 			time_to_string(inode->i_atime));
    801 		fprintf(out, "%s mtime: 0x%08x:%08x -- %s", prefix,
    802 			inode->i_mtime, large_inode->i_mtime_extra,
    803 			time_to_string(inode->i_mtime));
    804 		fprintf(out, "%scrtime: 0x%08x:%08x -- %s", prefix,
    805 			large_inode->i_crtime, large_inode->i_crtime_extra,
    806 			time_to_string(large_inode->i_crtime));
    807 	} else {
    808 		fprintf(out, "%sctime: 0x%08x -- %s", prefix, inode->i_ctime,
    809 			time_to_string(inode->i_ctime));
    810 		fprintf(out, "%satime: 0x%08x -- %s", prefix, inode->i_atime,
    811 			time_to_string(inode->i_atime));
    812 		fprintf(out, "%smtime: 0x%08x -- %s", prefix, inode->i_mtime,
    813 			time_to_string(inode->i_mtime));
    814 	}
    815 	if (inode->i_dtime)
    816 	  fprintf(out, "%sdtime: 0x%08x -- %s", prefix, inode->i_dtime,
    817 		  time_to_string(inode->i_dtime));
    818 	if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
    819 		internal_dump_inode_extra(out, prefix, inode_num,
    820 					  (struct ext2_inode_large *) inode);
    821 	if (LINUX_S_ISLNK(inode->i_mode) && ext2fs_inode_data_blocks(current_fs,inode) == 0)
    822 		fprintf(out, "%sFast_link_dest: %.*s\n", prefix,
    823 			(int) inode->i_size, (char *)inode->i_block);
    824 	else if (LINUX_S_ISBLK(inode->i_mode) || LINUX_S_ISCHR(inode->i_mode)) {
    825 		int major, minor;
    826 		const char *devnote;
    827 
    828 		if (inode->i_block[0]) {
    829 			major = (inode->i_block[0] >> 8) & 255;
    830 			minor = inode->i_block[0] & 255;
    831 			devnote = "";
    832 		} else {
    833 			major = (inode->i_block[1] & 0xfff00) >> 8;
    834 			minor = ((inode->i_block[1] & 0xff) |
    835 				 ((inode->i_block[1] >> 12) & 0xfff00));
    836 			devnote = "(New-style) ";
    837 		}
    838 		fprintf(out, "%sDevice major/minor number: %02d:%02d (hex %02x:%02x)\n",
    839 			devnote, major, minor, major, minor);
    840 	} else if (do_dump_blocks) {
    841 		if (inode->i_flags & EXT4_EXTENTS_FL)
    842 			dump_extents(out, prefix, inode_num,
    843 				     DUMP_LEAF_EXTENTS|DUMP_NODE_EXTENTS, 0, 0);
    844 		else
    845 			dump_blocks(out, prefix, inode_num);
    846 	}
    847 }
    848 
    849 static void dump_inode(ext2_ino_t inode_num, struct ext2_inode *inode)
    850 {
    851 	FILE	*out;
    852 
    853 	out = open_pager();
    854 	internal_dump_inode(out, "", inode_num, inode, 1);
    855 	close_pager(out);
    856 }
    857 
    858 void do_stat(int argc, char *argv[])
    859 {
    860 	ext2_ino_t	inode;
    861 	struct ext2_inode * inode_buf;
    862 
    863 	if (check_fs_open(argv[0]))
    864 		return;
    865 
    866 	inode_buf = (struct ext2_inode *)
    867 			malloc(EXT2_INODE_SIZE(current_fs->super));
    868 	if (!inode_buf) {
    869 		fprintf(stderr, "do_stat: can't allocate buffer\n");
    870 		return;
    871 	}
    872 
    873 	if (common_inode_args_process(argc, argv, &inode, 0)) {
    874 		free(inode_buf);
    875 		return;
    876 	}
    877 
    878 	if (debugfs_read_inode_full(inode, inode_buf, argv[0],
    879 					EXT2_INODE_SIZE(current_fs->super))) {
    880 		free(inode_buf);
    881 		return;
    882 	}
    883 
    884 	dump_inode(inode, inode_buf);
    885 	free(inode_buf);
    886 	return;
    887 }
    888 
    889 void do_dump_extents(int argc, char **argv)
    890 {
    891 	struct ext2_inode inode;
    892 	ext2_ino_t	ino;
    893 	FILE		*out;
    894 	int		c, flags = 0;
    895 	int		logical_width;
    896 	int		physical_width;
    897 
    898 	reset_getopt();
    899 	while ((c = getopt(argc, argv, "nl")) != EOF) {
    900 		switch (c) {
    901 		case 'n':
    902 			flags |= DUMP_NODE_EXTENTS;
    903 			break;
    904 		case 'l':
    905 			flags |= DUMP_LEAF_EXTENTS;
    906 			break;
    907 		}
    908 	}
    909 
    910 	if (argc != optind + 1) {
    911 		com_err(0, 0, "Usage: dump_extents [-n] [-l] file");
    912 		return;
    913 	}
    914 
    915 	if (flags == 0)
    916 		flags = DUMP_NODE_EXTENTS | DUMP_LEAF_EXTENTS;
    917 	flags |= DUMP_EXTENT_TABLE;
    918 
    919 	if (check_fs_open(argv[0]))
    920 		return;
    921 
    922 	ino = string_to_inode(argv[optind]);
    923 	if (ino == 0)
    924 		return;
    925 
    926 	if (debugfs_read_inode(ino, &inode, argv[0]))
    927 		return;
    928 
    929 	if ((inode.i_flags & EXT4_EXTENTS_FL) == 0) {
    930 		fprintf(stderr, "%s: does not uses extent block maps\n",
    931 			argv[optind]);
    932 		return;
    933 	}
    934 
    935 	logical_width = int_log10((EXT2_I_SIZE(&inode)+current_fs->blocksize-1)/
    936 				  current_fs->blocksize) + 1;
    937 	if (logical_width < 5)
    938 		logical_width = 5;
    939 	physical_width = int_log10(ext2fs_blocks_count(current_fs->super)) + 1;
    940 	if (physical_width < 5)
    941 		physical_width = 5;
    942 
    943 	out = open_pager();
    944 	dump_extents(out, "", ino, flags, logical_width, physical_width);
    945 	close_pager(out);
    946 	return;
    947 }
    948 
    949 static int print_blocks_proc(ext2_filsys fs EXT2FS_ATTR((unused)),
    950 			     blk64_t *blocknr,
    951 			     e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
    952 			     blk64_t ref_block EXT2FS_ATTR((unused)),
    953 			     int ref_offset EXT2FS_ATTR((unused)),
    954 			     void *private EXT2FS_ATTR((unused)))
    955 {
    956 	printf("%llu ", *blocknr);
    957 	return 0;
    958 }
    959 
    960 void do_blocks(int argc, char *argv[])
    961 {
    962 	ext2_ino_t	inode;
    963 
    964 	if (check_fs_open(argv[0]))
    965 		return;
    966 
    967 	if (common_inode_args_process(argc, argv, &inode, 0)) {
    968 		return;
    969 	}
    970 
    971 	ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL,
    972 			      print_blocks_proc, NULL);
    973 	fputc('\n', stdout);
    974 	return;
    975 }
    976 
    977 void do_chroot(int argc, char *argv[])
    978 {
    979 	ext2_ino_t inode;
    980 	int retval;
    981 
    982 	if (common_inode_args_process(argc, argv, &inode, 0))
    983 		return;
    984 
    985 	retval = ext2fs_check_directory(current_fs, inode);
    986 	if (retval)  {
    987 		com_err(argv[1], retval, 0);
    988 		return;
    989 	}
    990 	root = inode;
    991 }
    992 
    993 #ifndef READ_ONLY
    994 void do_clri(int argc, char *argv[])
    995 {
    996 	ext2_ino_t inode;
    997 	struct ext2_inode inode_buf;
    998 
    999 	if (common_inode_args_process(argc, argv, &inode, CHECK_FS_RW))
   1000 		return;
   1001 
   1002 	if (debugfs_read_inode(inode, &inode_buf, argv[0]))
   1003 		return;
   1004 	memset(&inode_buf, 0, sizeof(inode_buf));
   1005 	if (debugfs_write_inode(inode, &inode_buf, argv[0]))
   1006 		return;
   1007 }
   1008 
   1009 void do_freei(int argc, char *argv[])
   1010 {
   1011 	unsigned int	len = 1;
   1012 	int		err = 0;
   1013 	ext2_ino_t	inode;
   1014 
   1015 	if (common_args_process(argc, argv, 2, 3, argv[0], "<file> [num]",
   1016 				CHECK_FS_RW | CHECK_FS_BITMAPS))
   1017 		return;
   1018 	if (check_fs_read_write(argv[0]))
   1019 		return;
   1020 
   1021 	inode = string_to_inode(argv[1]);
   1022 	if (!inode)
   1023 		return;
   1024 
   1025 	if (argc == 3) {
   1026 		len = parse_ulong(argv[2], argv[0], "length", &err);
   1027 		if (err)
   1028 			return;
   1029 	}
   1030 
   1031 	if (len == 1 &&
   1032 	    !ext2fs_test_inode_bitmap2(current_fs->inode_map,inode))
   1033 		com_err(argv[0], 0, "Warning: inode already clear");
   1034 	while (len-- > 0)
   1035 		ext2fs_unmark_inode_bitmap2(current_fs->inode_map, inode++);
   1036 	ext2fs_mark_ib_dirty(current_fs);
   1037 }
   1038 
   1039 void do_seti(int argc, char *argv[])
   1040 {
   1041 	unsigned int	len = 1;
   1042 	int		err = 0;
   1043 	ext2_ino_t	inode;
   1044 
   1045 	if (common_args_process(argc, argv, 2, 3, argv[0], "<file> [num]",
   1046 				CHECK_FS_RW | CHECK_FS_BITMAPS))
   1047 		return;
   1048 	if (check_fs_read_write(argv[0]))
   1049 		return;
   1050 
   1051 	inode = string_to_inode(argv[1]);
   1052 	if (!inode)
   1053 		return;
   1054 
   1055 	if (argc == 3) {
   1056 		len = parse_ulong(argv[2], argv[0], "length", &err);
   1057 		if (err)
   1058 			return;
   1059 	}
   1060 
   1061 	if ((len == 1) &&
   1062 	    ext2fs_test_inode_bitmap2(current_fs->inode_map,inode))
   1063 		com_err(argv[0], 0, "Warning: inode already set");
   1064 	while (len-- > 0)
   1065 		ext2fs_mark_inode_bitmap2(current_fs->inode_map, inode++);
   1066 	ext2fs_mark_ib_dirty(current_fs);
   1067 }
   1068 #endif /* READ_ONLY */
   1069 
   1070 void do_testi(int argc, char *argv[])
   1071 {
   1072 	ext2_ino_t inode;
   1073 
   1074 	if (common_inode_args_process(argc, argv, &inode, CHECK_FS_BITMAPS))
   1075 		return;
   1076 
   1077 	if (ext2fs_test_inode_bitmap2(current_fs->inode_map,inode))
   1078 		printf("Inode %u is marked in use\n", inode);
   1079 	else
   1080 		printf("Inode %u is not in use\n", inode);
   1081 }
   1082 
   1083 #ifndef READ_ONLY
   1084 void do_freeb(int argc, char *argv[])
   1085 {
   1086 	blk64_t block;
   1087 	blk64_t count = 1;
   1088 
   1089 	if (common_block_args_process(argc, argv, &block, &count))
   1090 		return;
   1091 	if (check_fs_read_write(argv[0]))
   1092 		return;
   1093 	while (count-- > 0) {
   1094 		if (!ext2fs_test_block_bitmap2(current_fs->block_map,block))
   1095 			com_err(argv[0], 0, "Warning: block %llu already clear",
   1096 				block);
   1097 		ext2fs_unmark_block_bitmap2(current_fs->block_map,block);
   1098 		block++;
   1099 	}
   1100 	ext2fs_mark_bb_dirty(current_fs);
   1101 }
   1102 
   1103 void do_setb(int argc, char *argv[])
   1104 {
   1105 	blk64_t block;
   1106 	blk64_t count = 1;
   1107 
   1108 	if (common_block_args_process(argc, argv, &block, &count))
   1109 		return;
   1110 	if (check_fs_read_write(argv[0]))
   1111 		return;
   1112 	while (count-- > 0) {
   1113 		if (ext2fs_test_block_bitmap2(current_fs->block_map,block))
   1114 			com_err(argv[0], 0, "Warning: block %llu already set",
   1115 				block);
   1116 		ext2fs_mark_block_bitmap2(current_fs->block_map,block);
   1117 		block++;
   1118 	}
   1119 	ext2fs_mark_bb_dirty(current_fs);
   1120 }
   1121 #endif /* READ_ONLY */
   1122 
   1123 void do_testb(int argc, char *argv[])
   1124 {
   1125 	blk64_t block;
   1126 	blk64_t count = 1;
   1127 
   1128 	if (common_block_args_process(argc, argv, &block, &count))
   1129 		return;
   1130 	while (count-- > 0) {
   1131 		if (ext2fs_test_block_bitmap2(current_fs->block_map,block))
   1132 			printf("Block %llu marked in use\n", block);
   1133 		else
   1134 			printf("Block %llu not in use\n", block);
   1135 		block++;
   1136 	}
   1137 }
   1138 
   1139 #ifndef READ_ONLY
   1140 static void modify_u8(char *com, const char *prompt,
   1141 		      const char *format, __u8 *val)
   1142 {
   1143 	char buf[200];
   1144 	unsigned long v;
   1145 	char *tmp;
   1146 
   1147 	sprintf(buf, format, *val);
   1148 	printf("%30s    [%s] ", prompt, buf);
   1149 	if (!fgets(buf, sizeof(buf), stdin))
   1150 		return;
   1151 	if (buf[strlen (buf) - 1] == '\n')
   1152 		buf[strlen (buf) - 1] = '\0';
   1153 	if (!buf[0])
   1154 		return;
   1155 	v = strtoul(buf, &tmp, 0);
   1156 	if (*tmp)
   1157 		com_err(com, 0, "Bad value - %s", buf);
   1158 	else
   1159 		*val = v;
   1160 }
   1161 
   1162 static void modify_u16(char *com, const char *prompt,
   1163 		       const char *format, __u16 *val)
   1164 {
   1165 	char buf[200];
   1166 	unsigned long v;
   1167 	char *tmp;
   1168 
   1169 	sprintf(buf, format, *val);
   1170 	printf("%30s    [%s] ", prompt, buf);
   1171 	if (!fgets(buf, sizeof(buf), stdin))
   1172 		return;
   1173 	if (buf[strlen (buf) - 1] == '\n')
   1174 		buf[strlen (buf) - 1] = '\0';
   1175 	if (!buf[0])
   1176 		return;
   1177 	v = strtoul(buf, &tmp, 0);
   1178 	if (*tmp)
   1179 		com_err(com, 0, "Bad value - %s", buf);
   1180 	else
   1181 		*val = v;
   1182 }
   1183 
   1184 static void modify_u32(char *com, const char *prompt,
   1185 		       const char *format, __u32 *val)
   1186 {
   1187 	char buf[200];
   1188 	unsigned long v;
   1189 	char *tmp;
   1190 
   1191 	sprintf(buf, format, *val);
   1192 	printf("%30s    [%s] ", prompt, buf);
   1193 	if (!fgets(buf, sizeof(buf), stdin))
   1194 		return;
   1195 	if (buf[strlen (buf) - 1] == '\n')
   1196 		buf[strlen (buf) - 1] = '\0';
   1197 	if (!buf[0])
   1198 		return;
   1199 	v = strtoul(buf, &tmp, 0);
   1200 	if (*tmp)
   1201 		com_err(com, 0, "Bad value - %s", buf);
   1202 	else
   1203 		*val = v;
   1204 }
   1205 
   1206 
   1207 void do_modify_inode(int argc, char *argv[])
   1208 {
   1209 	struct ext2_inode inode;
   1210 	ext2_ino_t	inode_num;
   1211 	int 		i;
   1212 	unsigned char	*frag, *fsize;
   1213 	char		buf[80];
   1214 	int 		os;
   1215 	const char	*hex_format = "0x%x";
   1216 	const char	*octal_format = "0%o";
   1217 	const char	*decimal_format = "%d";
   1218 	const char	*unsignedlong_format = "%lu";
   1219 
   1220 	if (common_inode_args_process(argc, argv, &inode_num, CHECK_FS_RW))
   1221 		return;
   1222 
   1223 	os = current_fs->super->s_creator_os;
   1224 
   1225 	if (debugfs_read_inode(inode_num, &inode, argv[1]))
   1226 		return;
   1227 
   1228 	modify_u16(argv[0], "Mode", octal_format, &inode.i_mode);
   1229 	modify_u16(argv[0], "User ID", decimal_format, &inode.i_uid);
   1230 	modify_u16(argv[0], "Group ID", decimal_format, &inode.i_gid);
   1231 	modify_u32(argv[0], "Size", unsignedlong_format, &inode.i_size);
   1232 	modify_u32(argv[0], "Creation time", decimal_format, &inode.i_ctime);
   1233 	modify_u32(argv[0], "Modification time", decimal_format, &inode.i_mtime);
   1234 	modify_u32(argv[0], "Access time", decimal_format, &inode.i_atime);
   1235 	modify_u32(argv[0], "Deletion time", decimal_format, &inode.i_dtime);
   1236 	modify_u16(argv[0], "Link count", decimal_format, &inode.i_links_count);
   1237 	if (os == EXT2_OS_LINUX)
   1238 		modify_u16(argv[0], "Block count high", unsignedlong_format,
   1239 			   &inode.osd2.linux2.l_i_blocks_hi);
   1240 	modify_u32(argv[0], "Block count", unsignedlong_format, &inode.i_blocks);
   1241 	modify_u32(argv[0], "File flags", hex_format, &inode.i_flags);
   1242 	modify_u32(argv[0], "Generation", hex_format, &inode.i_generation);
   1243 #if 0
   1244 	modify_u32(argv[0], "Reserved1", decimal_format, &inode.i_reserved1);
   1245 #endif
   1246 	modify_u32(argv[0], "File acl", decimal_format, &inode.i_file_acl);
   1247 	if (LINUX_S_ISDIR(inode.i_mode))
   1248 		modify_u32(argv[0], "Directory acl", decimal_format, &inode.i_dir_acl);
   1249 	else
   1250 		modify_u32(argv[0], "High 32bits of size", decimal_format, &inode.i_size_high);
   1251 
   1252 	if (os == EXT2_OS_HURD)
   1253 		modify_u32(argv[0], "Translator Block",
   1254 			    decimal_format, &inode.osd1.hurd1.h_i_translator);
   1255 
   1256 	modify_u32(argv[0], "Fragment address", decimal_format, &inode.i_faddr);
   1257 	switch (os) {
   1258 	    case EXT2_OS_HURD:
   1259 		frag = &inode.osd2.hurd2.h_i_frag;
   1260 		fsize = &inode.osd2.hurd2.h_i_fsize;
   1261 		break;
   1262 	    default:
   1263 		frag = fsize = 0;
   1264 	}
   1265 	if (frag)
   1266 		modify_u8(argv[0], "Fragment number", decimal_format, frag);
   1267 	if (fsize)
   1268 		modify_u8(argv[0], "Fragment size", decimal_format, fsize);
   1269 
   1270 	for (i=0;  i < EXT2_NDIR_BLOCKS; i++) {
   1271 		sprintf(buf, "Direct Block #%d", i);
   1272 		modify_u32(argv[0], buf, decimal_format, &inode.i_block[i]);
   1273 	}
   1274 	modify_u32(argv[0], "Indirect Block", decimal_format,
   1275 		    &inode.i_block[EXT2_IND_BLOCK]);
   1276 	modify_u32(argv[0], "Double Indirect Block", decimal_format,
   1277 		    &inode.i_block[EXT2_DIND_BLOCK]);
   1278 	modify_u32(argv[0], "Triple Indirect Block", decimal_format,
   1279 		    &inode.i_block[EXT2_TIND_BLOCK]);
   1280 	if (debugfs_write_inode(inode_num, &inode, argv[1]))
   1281 		return;
   1282 }
   1283 #endif /* READ_ONLY */
   1284 
   1285 void do_change_working_dir(int argc, char *argv[])
   1286 {
   1287 	ext2_ino_t	inode;
   1288 	int		retval;
   1289 
   1290 	if (common_inode_args_process(argc, argv, &inode, 0))
   1291 		return;
   1292 
   1293 	retval = ext2fs_check_directory(current_fs, inode);
   1294 	if (retval) {
   1295 		com_err(argv[1], retval, 0);
   1296 		return;
   1297 	}
   1298 	cwd = inode;
   1299 	return;
   1300 }
   1301 
   1302 void do_print_working_directory(int argc, char *argv[])
   1303 {
   1304 	int	retval;
   1305 	char	*pathname = NULL;
   1306 
   1307 	if (common_args_process(argc, argv, 1, 1,
   1308 				"print_working_directory", "", 0))
   1309 		return;
   1310 
   1311 	retval = ext2fs_get_pathname(current_fs, cwd, 0, &pathname);
   1312 	if (retval) {
   1313 		com_err(argv[0], retval,
   1314 			"while trying to get pathname of cwd");
   1315 	}
   1316 	printf("[pwd]   INODE: %6u  PATH: %s\n",
   1317 	       cwd, pathname ? pathname : "NULL");
   1318         if (pathname) {
   1319 		free(pathname);
   1320 		pathname = NULL;
   1321         }
   1322 	retval = ext2fs_get_pathname(current_fs, root, 0, &pathname);
   1323 	if (retval) {
   1324 		com_err(argv[0], retval,
   1325 			"while trying to get pathname of root");
   1326 	}
   1327 	printf("[root]  INODE: %6u  PATH: %s\n",
   1328 	       root, pathname ? pathname : "NULL");
   1329 	if (pathname) {
   1330 		free(pathname);
   1331 		pathname = NULL;
   1332 	}
   1333 	return;
   1334 }
   1335 
   1336 #ifndef READ_ONLY
   1337 static void make_link(char *sourcename, char *destname)
   1338 {
   1339 	ext2_ino_t	ino;
   1340 	struct ext2_inode inode;
   1341 	int		retval;
   1342 	ext2_ino_t	dir;
   1343 	char		*dest, *cp, *base_name;
   1344 
   1345 	/*
   1346 	 * Get the source inode
   1347 	 */
   1348 	ino = string_to_inode(sourcename);
   1349 	if (!ino)
   1350 		return;
   1351 	base_name = strrchr(sourcename, '/');
   1352 	if (base_name)
   1353 		base_name++;
   1354 	else
   1355 		base_name = sourcename;
   1356 	/*
   1357 	 * Figure out the destination.  First see if it exists and is
   1358 	 * a directory.
   1359 	 */
   1360 	if (! (retval=ext2fs_namei(current_fs, root, cwd, destname, &dir)))
   1361 		dest = base_name;
   1362 	else {
   1363 		/*
   1364 		 * OK, it doesn't exist.  See if it is
   1365 		 * '<dir>/basename' or 'basename'
   1366 		 */
   1367 		cp = strrchr(destname, '/');
   1368 		if (cp) {
   1369 			*cp = 0;
   1370 			dir = string_to_inode(destname);
   1371 			if (!dir)
   1372 				return;
   1373 			dest = cp+1;
   1374 		} else {
   1375 			dir = cwd;
   1376 			dest = destname;
   1377 		}
   1378 	}
   1379 
   1380 	if (debugfs_read_inode(ino, &inode, sourcename))
   1381 		return;
   1382 
   1383 	retval = ext2fs_link(current_fs, dir, dest, ino,
   1384 			     ext2_file_type(inode.i_mode));
   1385 	if (retval)
   1386 		com_err("make_link", retval, 0);
   1387 	return;
   1388 }
   1389 
   1390 
   1391 void do_link(int argc, char *argv[])
   1392 {
   1393 	if (common_args_process(argc, argv, 3, 3, "link",
   1394 				"<source file> <dest_name>", CHECK_FS_RW))
   1395 		return;
   1396 
   1397 	make_link(argv[1], argv[2]);
   1398 }
   1399 
   1400 static int mark_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
   1401 			    e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
   1402 			    blk64_t ref_block EXT2FS_ATTR((unused)),
   1403 			    int ref_offset EXT2FS_ATTR((unused)),
   1404 			    void *private EXT2FS_ATTR((unused)))
   1405 {
   1406 	blk64_t	block;
   1407 
   1408 	block = *blocknr;
   1409 	ext2fs_block_alloc_stats2(fs, block, +1);
   1410 	return 0;
   1411 }
   1412 
   1413 void do_undel(int argc, char *argv[])
   1414 {
   1415 	ext2_ino_t	ino;
   1416 	struct ext2_inode inode;
   1417 
   1418 	if (common_args_process(argc, argv, 2, 3, "undelete",
   1419 				"<inode_num> [dest_name]",
   1420 				CHECK_FS_RW | CHECK_FS_BITMAPS))
   1421 		return;
   1422 
   1423 	ino = string_to_inode(argv[1]);
   1424 	if (!ino)
   1425 		return;
   1426 
   1427 	if (debugfs_read_inode(ino, &inode, argv[1]))
   1428 		return;
   1429 
   1430 	if (ext2fs_test_inode_bitmap2(current_fs->inode_map, ino)) {
   1431 		com_err(argv[1], 0, "Inode is not marked as deleted");
   1432 		return;
   1433 	}
   1434 
   1435 	/*
   1436 	 * XXX this function doesn't handle changing the links count on the
   1437 	 * parent directory when undeleting a directory.
   1438 	 */
   1439 	inode.i_links_count = LINUX_S_ISDIR(inode.i_mode) ? 2 : 1;
   1440 	inode.i_dtime = 0;
   1441 
   1442 	if (debugfs_write_inode(ino, &inode, argv[0]))
   1443 		return;
   1444 
   1445 	ext2fs_block_iterate3(current_fs, ino, BLOCK_FLAG_READ_ONLY, NULL,
   1446 			      mark_blocks_proc, NULL);
   1447 
   1448 	ext2fs_inode_alloc_stats2(current_fs, ino, +1, 0);
   1449 
   1450 	if (argc > 2)
   1451 		make_link(argv[1], argv[2]);
   1452 }
   1453 
   1454 static void unlink_file_by_name(char *filename)
   1455 {
   1456 	int		retval;
   1457 	ext2_ino_t	dir;
   1458 	char		*base_name;
   1459 
   1460 	base_name = strrchr(filename, '/');
   1461 	if (base_name) {
   1462 		*base_name++ = '\0';
   1463 		dir = string_to_inode(filename);
   1464 		if (!dir)
   1465 			return;
   1466 	} else {
   1467 		dir = cwd;
   1468 		base_name = filename;
   1469 	}
   1470 	retval = ext2fs_unlink(current_fs, dir, base_name, 0, 0);
   1471 	if (retval)
   1472 		com_err("unlink_file_by_name", retval, 0);
   1473 	return;
   1474 }
   1475 
   1476 void do_unlink(int argc, char *argv[])
   1477 {
   1478 	if (common_args_process(argc, argv, 2, 2, "link",
   1479 				"<pathname>", CHECK_FS_RW))
   1480 		return;
   1481 
   1482 	unlink_file_by_name(argv[1]);
   1483 }
   1484 #endif /* READ_ONLY */
   1485 
   1486 void do_find_free_block(int argc, char *argv[])
   1487 {
   1488 	blk64_t	free_blk, goal, first_free = 0;
   1489  	int		count;
   1490 	errcode_t	retval;
   1491 	char		*tmp;
   1492 
   1493 	if ((argc > 3) || (argc==2 && *argv[1] == '?')) {
   1494 		com_err(argv[0], 0, "Usage: find_free_block [count [goal]]");
   1495 		return;
   1496 	}
   1497 	if (check_fs_open(argv[0]))
   1498 		return;
   1499 
   1500 	if (argc > 1) {
   1501 		count = strtol(argv[1],&tmp,0);
   1502 		if (*tmp) {
   1503 			com_err(argv[0], 0, "Bad count - %s", argv[1]);
   1504 			return;
   1505 		}
   1506  	} else
   1507 		count = 1;
   1508 
   1509 	if (argc > 2) {
   1510 		goal = strtol(argv[2], &tmp, 0);
   1511 		if (*tmp) {
   1512 			com_err(argv[0], 0, "Bad goal - %s", argv[1]);
   1513 			return;
   1514 		}
   1515 	}
   1516 	else
   1517 		goal = current_fs->super->s_first_data_block;
   1518 
   1519 	printf("Free blocks found: ");
   1520 	free_blk = goal - 1;
   1521 	while (count-- > 0) {
   1522 		retval = ext2fs_new_block2(current_fs, free_blk + 1, 0,
   1523 					   &free_blk);
   1524 		if (first_free) {
   1525 			if (first_free == free_blk)
   1526 				break;
   1527 		} else
   1528 			first_free = free_blk;
   1529 		if (retval) {
   1530 			com_err("ext2fs_new_block", retval, 0);
   1531 			return;
   1532 		} else
   1533 			printf("%llu ", free_blk);
   1534 	}
   1535  	printf("\n");
   1536 }
   1537 
   1538 void do_find_free_inode(int argc, char *argv[])
   1539 {
   1540 	ext2_ino_t	free_inode, dir;
   1541 	int		mode;
   1542 	int		retval;
   1543 	char		*tmp;
   1544 
   1545 	if (argc > 3 || (argc>1 && *argv[1] == '?')) {
   1546 		com_err(argv[0], 0, "Usage: find_free_inode [dir] [mode]");
   1547 		return;
   1548 	}
   1549 	if (check_fs_open(argv[0]))
   1550 		return;
   1551 
   1552 	if (argc > 1) {
   1553 		dir = strtol(argv[1], &tmp, 0);
   1554 		if (*tmp) {
   1555 			com_err(argv[0], 0, "Bad dir - %s", argv[1]);
   1556 			return;
   1557 		}
   1558 	}
   1559 	else
   1560 		dir = root;
   1561 	if (argc > 2) {
   1562 		mode = strtol(argv[2], &tmp, 0);
   1563 		if (*tmp) {
   1564 			com_err(argv[0], 0, "Bad mode - %s", argv[2]);
   1565 			return;
   1566 		}
   1567 	} else
   1568 		mode = 010755;
   1569 
   1570 	retval = ext2fs_new_inode(current_fs, dir, mode, 0, &free_inode);
   1571 	if (retval)
   1572 		com_err("ext2fs_new_inode", retval, 0);
   1573 	else
   1574 		printf("Free inode found: %u\n", free_inode);
   1575 }
   1576 
   1577 #ifndef READ_ONLY
   1578 static errcode_t copy_file(int fd, ext2_ino_t newfile, int bufsize, int make_holes)
   1579 {
   1580 	ext2_file_t	e2_file;
   1581 	errcode_t	retval;
   1582 	int		got;
   1583 	unsigned int	written;
   1584 	char		*buf;
   1585 	char		*ptr;
   1586 	char		*zero_buf;
   1587 	int		cmp;
   1588 
   1589 	retval = ext2fs_file_open(current_fs, newfile,
   1590 				  EXT2_FILE_WRITE, &e2_file);
   1591 	if (retval)
   1592 		return retval;
   1593 
   1594 	retval = ext2fs_get_mem(bufsize, &buf);
   1595 	if (retval) {
   1596 		com_err("copy_file", retval, "can't allocate buffer\n");
   1597 		return retval;
   1598 	}
   1599 
   1600 	/* This is used for checking whether the whole block is zero */
   1601 	retval = ext2fs_get_memzero(bufsize, &zero_buf);
   1602 	if (retval) {
   1603 		com_err("copy_file", retval, "can't allocate buffer\n");
   1604 		ext2fs_free_mem(&buf);
   1605 		return retval;
   1606 	}
   1607 
   1608 	while (1) {
   1609 		got = read(fd, buf, bufsize);
   1610 		if (got == 0)
   1611 			break;
   1612 		if (got < 0) {
   1613 			retval = errno;
   1614 			goto fail;
   1615 		}
   1616 		ptr = buf;
   1617 
   1618 		/* Sparse copy */
   1619 		if (make_holes) {
   1620 			/* Check whether all is zero */
   1621 			cmp = memcmp(ptr, zero_buf, got);
   1622 			if (cmp == 0) {
   1623 				 /* The whole block is zero, make a hole */
   1624 				retval = ext2fs_file_lseek(e2_file, got, EXT2_SEEK_CUR, NULL);
   1625 				if (retval)
   1626 					goto fail;
   1627 				got = 0;
   1628 			}
   1629 		}
   1630 
   1631 		/* Normal copy */
   1632 		while (got > 0) {
   1633 			retval = ext2fs_file_write(e2_file, ptr,
   1634 						   got, &written);
   1635 			if (retval)
   1636 				goto fail;
   1637 
   1638 			got -= written;
   1639 			ptr += written;
   1640 		}
   1641 	}
   1642 	ext2fs_free_mem(&buf);
   1643 	ext2fs_free_mem(&zero_buf);
   1644 	retval = ext2fs_file_close(e2_file);
   1645 	return retval;
   1646 
   1647 fail:
   1648 	ext2fs_free_mem(&buf);
   1649 	ext2fs_free_mem(&zero_buf);
   1650 	(void) ext2fs_file_close(e2_file);
   1651 	return retval;
   1652 }
   1653 
   1654 
   1655 void do_write(int argc, char *argv[])
   1656 {
   1657 	int		fd;
   1658 	struct stat	statbuf;
   1659 	ext2_ino_t	newfile;
   1660 	errcode_t	retval;
   1661 	struct ext2_inode inode;
   1662 	int		bufsize = IO_BUFSIZE;
   1663 	int		make_holes = 0;
   1664 
   1665 	if (common_args_process(argc, argv, 3, 3, "write",
   1666 				"<native file> <new file>", CHECK_FS_RW))
   1667 		return;
   1668 
   1669 	fd = open(argv[1], O_RDONLY);
   1670 	if (fd < 0) {
   1671 		com_err(argv[1], errno, 0);
   1672 		return;
   1673 	}
   1674 	if (fstat(fd, &statbuf) < 0) {
   1675 		com_err(argv[1], errno, 0);
   1676 		close(fd);
   1677 		return;
   1678 	}
   1679 
   1680 	retval = ext2fs_namei(current_fs, root, cwd, argv[2], &newfile);
   1681 	if (retval == 0) {
   1682 		com_err(argv[0], 0, "The file '%s' already exists\n", argv[2]);
   1683 		close(fd);
   1684 		return;
   1685 	}
   1686 
   1687 	retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
   1688 	if (retval) {
   1689 		com_err(argv[0], retval, 0);
   1690 		close(fd);
   1691 		return;
   1692 	}
   1693 	printf("Allocated inode: %u\n", newfile);
   1694 	retval = ext2fs_link(current_fs, cwd, argv[2], newfile,
   1695 			     EXT2_FT_REG_FILE);
   1696 	if (retval == EXT2_ET_DIR_NO_SPACE) {
   1697 		retval = ext2fs_expand_dir(current_fs, cwd);
   1698 		if (retval) {
   1699 			com_err(argv[0], retval, "while expanding directory");
   1700 			close(fd);
   1701 			return;
   1702 		}
   1703 		retval = ext2fs_link(current_fs, cwd, argv[2], newfile,
   1704 				     EXT2_FT_REG_FILE);
   1705 	}
   1706 	if (retval) {
   1707 		com_err(argv[2], retval, 0);
   1708 		close(fd);
   1709 		return;
   1710 	}
   1711         if (ext2fs_test_inode_bitmap2(current_fs->inode_map,newfile))
   1712 		com_err(argv[0], 0, "Warning: inode already set");
   1713 	ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0);
   1714 	memset(&inode, 0, sizeof(inode));
   1715 	inode.i_mode = (statbuf.st_mode & ~LINUX_S_IFMT) | LINUX_S_IFREG;
   1716 	inode.i_atime = inode.i_ctime = inode.i_mtime =
   1717 		current_fs->now ? current_fs->now : time(0);
   1718 	inode.i_links_count = 1;
   1719 	inode.i_size = statbuf.st_size;
   1720 	if (current_fs->super->s_feature_incompat &
   1721 	    EXT3_FEATURE_INCOMPAT_EXTENTS) {
   1722 		int i;
   1723 		struct ext3_extent_header *eh;
   1724 
   1725 		eh = (struct ext3_extent_header *) &inode.i_block[0];
   1726 		eh->eh_depth = 0;
   1727 		eh->eh_entries = 0;
   1728 		eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC);
   1729 		i = (sizeof(inode.i_block) - sizeof(*eh)) /
   1730 			sizeof(struct ext3_extent);
   1731 		eh->eh_max = ext2fs_cpu_to_le16(i);
   1732 		inode.i_flags |= EXT4_EXTENTS_FL;
   1733 	}
   1734 	if (debugfs_write_new_inode(newfile, &inode, argv[0])) {
   1735 		close(fd);
   1736 		return;
   1737 	}
   1738 	if (LINUX_S_ISREG(inode.i_mode)) {
   1739 		if (statbuf.st_blocks < statbuf.st_size / S_BLKSIZE) {
   1740 			make_holes = 1;
   1741 			/*
   1742 			 * Use I/O blocksize as buffer size when
   1743 			 * copying sparse files.
   1744 			 */
   1745 			bufsize = statbuf.st_blksize;
   1746 		}
   1747 		retval = copy_file(fd, newfile, bufsize, make_holes);
   1748 		if (retval)
   1749 			com_err("copy_file", retval, 0);
   1750 	}
   1751 	close(fd);
   1752 }
   1753 
   1754 void do_mknod(int argc, char *argv[])
   1755 {
   1756 	unsigned long	mode, major, minor;
   1757 	ext2_ino_t	newfile;
   1758 	errcode_t 	retval;
   1759 	struct ext2_inode inode;
   1760 	int		filetype, nr;
   1761 
   1762 	if (check_fs_open(argv[0]))
   1763 		return;
   1764 	if (argc < 3 || argv[2][1]) {
   1765 	usage:
   1766 		com_err(argv[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]");
   1767 		return;
   1768 	}
   1769 	mode = minor = major = 0;
   1770 	switch (argv[2][0]) {
   1771 		case 'p':
   1772 			mode = LINUX_S_IFIFO;
   1773 			filetype = EXT2_FT_FIFO;
   1774 			nr = 3;
   1775 			break;
   1776 		case 'c':
   1777 			mode = LINUX_S_IFCHR;
   1778 			filetype = EXT2_FT_CHRDEV;
   1779 			nr = 5;
   1780 			break;
   1781 		case 'b':
   1782 			mode = LINUX_S_IFBLK;
   1783 			filetype = EXT2_FT_BLKDEV;
   1784 			nr = 5;
   1785 			break;
   1786 		default:
   1787 			filetype = 0;
   1788 			nr = 0;
   1789 	}
   1790 	if (nr == 5) {
   1791 		major = strtoul(argv[3], argv+3, 0);
   1792 		minor = strtoul(argv[4], argv+4, 0);
   1793 		if (major > 65535 || minor > 65535 || argv[3][0] || argv[4][0])
   1794 			nr = 0;
   1795 	}
   1796 	if (argc != nr)
   1797 		goto usage;
   1798 	if (check_fs_read_write(argv[0]))
   1799 		return;
   1800 	retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
   1801 	if (retval) {
   1802 		com_err(argv[0], retval, 0);
   1803 		return;
   1804 	}
   1805 	printf("Allocated inode: %u\n", newfile);
   1806 	retval = ext2fs_link(current_fs, cwd, argv[1], newfile, filetype);
   1807 	if (retval == EXT2_ET_DIR_NO_SPACE) {
   1808 		retval = ext2fs_expand_dir(current_fs, cwd);
   1809 		if (retval) {
   1810 			com_err(argv[0], retval, "while expanding directory");
   1811 			return;
   1812 		}
   1813 		retval = ext2fs_link(current_fs, cwd, argv[1], newfile,
   1814 				     filetype);
   1815 	}
   1816 	if (retval) {
   1817 		com_err(argv[1], retval, 0);
   1818 		return;
   1819 	}
   1820         if (ext2fs_test_inode_bitmap2(current_fs->inode_map,newfile))
   1821 		com_err(argv[0], 0, "Warning: inode already set");
   1822 	ext2fs_inode_alloc_stats2(current_fs, newfile, +1, 0);
   1823 	memset(&inode, 0, sizeof(inode));
   1824 	inode.i_mode = mode;
   1825 	inode.i_atime = inode.i_ctime = inode.i_mtime =
   1826 		current_fs->now ? current_fs->now : time(0);
   1827 	if ((major < 256) && (minor < 256)) {
   1828 		inode.i_block[0] = major*256+minor;
   1829 		inode.i_block[1] = 0;
   1830 	} else {
   1831 		inode.i_block[0] = 0;
   1832 		inode.i_block[1] = (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
   1833 	}
   1834 	inode.i_links_count = 1;
   1835 	if (debugfs_write_new_inode(newfile, &inode, argv[0]))
   1836 		return;
   1837 }
   1838 
   1839 void do_mkdir(int argc, char *argv[])
   1840 {
   1841 	char	*cp;
   1842 	ext2_ino_t	parent;
   1843 	char	*name;
   1844 	errcode_t retval;
   1845 
   1846 	if (common_args_process(argc, argv, 2, 2, "mkdir",
   1847 				"<filename>", CHECK_FS_RW))
   1848 		return;
   1849 
   1850 	cp = strrchr(argv[1], '/');
   1851 	if (cp) {
   1852 		*cp = 0;
   1853 		parent = string_to_inode(argv[1]);
   1854 		if (!parent) {
   1855 			com_err(argv[1], ENOENT, 0);
   1856 			return;
   1857 		}
   1858 		name = cp+1;
   1859 	} else {
   1860 		parent = cwd;
   1861 		name = argv[1];
   1862 	}
   1863 
   1864 try_again:
   1865 	retval = ext2fs_mkdir(current_fs, parent, 0, name);
   1866 	if (retval == EXT2_ET_DIR_NO_SPACE) {
   1867 		retval = ext2fs_expand_dir(current_fs, parent);
   1868 		if (retval) {
   1869 			com_err(argv[0], retval, "while expanding directory");
   1870 			return;
   1871 		}
   1872 		goto try_again;
   1873 	}
   1874 	if (retval) {
   1875 		com_err("ext2fs_mkdir", retval, 0);
   1876 		return;
   1877 	}
   1878 
   1879 }
   1880 
   1881 static int release_blocks_proc(ext2_filsys fs, blk64_t *blocknr,
   1882 			       e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
   1883 			       blk64_t ref_block EXT2FS_ATTR((unused)),
   1884 			       int ref_offset EXT2FS_ATTR((unused)),
   1885 			       void *private EXT2FS_ATTR((unused)))
   1886 {
   1887 	blk64_t	block;
   1888 
   1889 	block = *blocknr;
   1890 	ext2fs_block_alloc_stats2(fs, block, -1);
   1891 	return 0;
   1892 }
   1893 
   1894 static void kill_file_by_inode(ext2_ino_t inode)
   1895 {
   1896 	struct ext2_inode inode_buf;
   1897 
   1898 	if (debugfs_read_inode(inode, &inode_buf, 0))
   1899 		return;
   1900 	inode_buf.i_dtime = current_fs->now ? current_fs->now : time(0);
   1901 	if (debugfs_write_inode(inode, &inode_buf, 0))
   1902 		return;
   1903 	if (!ext2fs_inode_has_valid_blocks2(current_fs, &inode_buf))
   1904 		return;
   1905 
   1906 	ext2fs_block_iterate3(current_fs, inode, BLOCK_FLAG_READ_ONLY, NULL,
   1907 			      release_blocks_proc, NULL);
   1908 	printf("\n");
   1909 	ext2fs_inode_alloc_stats2(current_fs, inode, -1,
   1910 				  LINUX_S_ISDIR(inode_buf.i_mode));
   1911 }
   1912 
   1913 
   1914 void do_kill_file(int argc, char *argv[])
   1915 {
   1916 	ext2_ino_t inode_num;
   1917 
   1918 	if (common_inode_args_process(argc, argv, &inode_num, CHECK_FS_RW))
   1919 		return;
   1920 
   1921 	kill_file_by_inode(inode_num);
   1922 }
   1923 
   1924 void do_rm(int argc, char *argv[])
   1925 {
   1926 	int retval;
   1927 	ext2_ino_t inode_num;
   1928 	struct ext2_inode inode;
   1929 
   1930 	if (common_args_process(argc, argv, 2, 2, "rm",
   1931 				"<filename>", CHECK_FS_RW))
   1932 		return;
   1933 
   1934 	retval = ext2fs_namei(current_fs, root, cwd, argv[1], &inode_num);
   1935 	if (retval) {
   1936 		com_err(argv[0], retval, "while trying to resolve filename");
   1937 		return;
   1938 	}
   1939 
   1940 	if (debugfs_read_inode(inode_num, &inode, argv[0]))
   1941 		return;
   1942 
   1943 	if (LINUX_S_ISDIR(inode.i_mode)) {
   1944 		com_err(argv[0], 0, "file is a directory");
   1945 		return;
   1946 	}
   1947 
   1948 	--inode.i_links_count;
   1949 	if (debugfs_write_inode(inode_num, &inode, argv[0]))
   1950 		return;
   1951 
   1952 	unlink_file_by_name(argv[1]);
   1953 	if (inode.i_links_count == 0)
   1954 		kill_file_by_inode(inode_num);
   1955 }
   1956 
   1957 struct rd_struct {
   1958 	ext2_ino_t	parent;
   1959 	int		empty;
   1960 };
   1961 
   1962 static int rmdir_proc(ext2_ino_t dir EXT2FS_ATTR((unused)),
   1963 		      int	entry EXT2FS_ATTR((unused)),
   1964 		      struct ext2_dir_entry *dirent,
   1965 		      int	offset EXT2FS_ATTR((unused)),
   1966 		      int	blocksize EXT2FS_ATTR((unused)),
   1967 		      char	*buf EXT2FS_ATTR((unused)),
   1968 		      void	*private)
   1969 {
   1970 	struct rd_struct *rds = (struct rd_struct *) private;
   1971 
   1972 	if (dirent->inode == 0)
   1973 		return 0;
   1974 	if (((dirent->name_len&0xFF) == 1) && (dirent->name[0] == '.'))
   1975 		return 0;
   1976 	if (((dirent->name_len&0xFF) == 2) && (dirent->name[0] == '.') &&
   1977 	    (dirent->name[1] == '.')) {
   1978 		rds->parent = dirent->inode;
   1979 		return 0;
   1980 	}
   1981 	rds->empty = 0;
   1982 	return 0;
   1983 }
   1984 
   1985 void do_rmdir(int argc, char *argv[])
   1986 {
   1987 	int retval;
   1988 	ext2_ino_t inode_num;
   1989 	struct ext2_inode inode;
   1990 	struct rd_struct rds;
   1991 
   1992 	if (common_args_process(argc, argv, 2, 2, "rmdir",
   1993 				"<filename>", CHECK_FS_RW))
   1994 		return;
   1995 
   1996 	retval = ext2fs_namei(current_fs, root, cwd, argv[1], &inode_num);
   1997 	if (retval) {
   1998 		com_err(argv[0], retval, "while trying to resolve filename");
   1999 		return;
   2000 	}
   2001 
   2002 	if (debugfs_read_inode(inode_num, &inode, argv[0]))
   2003 		return;
   2004 
   2005 	if (!LINUX_S_ISDIR(inode.i_mode)) {
   2006 		com_err(argv[0], 0, "file is not a directory");
   2007 		return;
   2008 	}
   2009 
   2010 	rds.parent = 0;
   2011 	rds.empty = 1;
   2012 
   2013 	retval = ext2fs_dir_iterate2(current_fs, inode_num, 0,
   2014 				    0, rmdir_proc, &rds);
   2015 	if (retval) {
   2016 		com_err(argv[0], retval, "while iterating over directory");
   2017 		return;
   2018 	}
   2019 	if (rds.empty == 0) {
   2020 		com_err(argv[0], 0, "directory not empty");
   2021 		return;
   2022 	}
   2023 
   2024 	inode.i_links_count = 0;
   2025 	if (debugfs_write_inode(inode_num, &inode, argv[0]))
   2026 		return;
   2027 
   2028 	unlink_file_by_name(argv[1]);
   2029 	kill_file_by_inode(inode_num);
   2030 
   2031 	if (rds.parent) {
   2032 		if (debugfs_read_inode(rds.parent, &inode, argv[0]))
   2033 			return;
   2034 		if (inode.i_links_count > 1)
   2035 			inode.i_links_count--;
   2036 		if (debugfs_write_inode(rds.parent, &inode, argv[0]))
   2037 			return;
   2038 	}
   2039 }
   2040 #endif /* READ_ONLY */
   2041 
   2042 void do_show_debugfs_params(int argc EXT2FS_ATTR((unused)),
   2043 			    char *argv[] EXT2FS_ATTR((unused)))
   2044 {
   2045 	if (current_fs)
   2046 		printf("Open mode: read-%s\n",
   2047 		       current_fs->flags & EXT2_FLAG_RW ? "write" : "only");
   2048 	printf("Filesystem in use: %s\n",
   2049 	       current_fs ? current_fs->device_name : "--none--");
   2050 }
   2051 
   2052 #ifndef READ_ONLY
   2053 void do_expand_dir(int argc, char *argv[])
   2054 {
   2055 	ext2_ino_t inode;
   2056 	int retval;
   2057 
   2058 	if (common_inode_args_process(argc, argv, &inode, CHECK_FS_RW))
   2059 		return;
   2060 
   2061 	retval = ext2fs_expand_dir(current_fs, inode);
   2062 	if (retval)
   2063 		com_err("ext2fs_expand_dir", retval, 0);
   2064 	return;
   2065 }
   2066 
   2067 void do_features(int argc, char *argv[])
   2068 {
   2069 	int	i;
   2070 
   2071 	if (check_fs_open(argv[0]))
   2072 		return;
   2073 
   2074 	if ((argc != 1) && check_fs_read_write(argv[0]))
   2075 		return;
   2076 	for (i=1; i < argc; i++) {
   2077 		if (e2p_edit_feature(argv[i],
   2078 				     &current_fs->super->s_feature_compat, 0))
   2079 			com_err(argv[0], 0, "Unknown feature: %s\n",
   2080 				argv[i]);
   2081 		else
   2082 			ext2fs_mark_super_dirty(current_fs);
   2083 	}
   2084 	print_features(current_fs->super, stdout);
   2085 }
   2086 #endif /* READ_ONLY */
   2087 
   2088 void do_bmap(int argc, char *argv[])
   2089 {
   2090 	ext2_ino_t	ino;
   2091 	blk64_t		blk, pblk;
   2092 	int		err;
   2093 	errcode_t	errcode;
   2094 
   2095 	if (common_args_process(argc, argv, 3, 3, argv[0],
   2096 				"<file> logical_blk", 0))
   2097 		return;
   2098 
   2099 	ino = string_to_inode(argv[1]);
   2100 	if (!ino)
   2101 		return;
   2102 	err = strtoblk(argv[0], argv[2], &blk);
   2103 	if (err)
   2104 		return;
   2105 
   2106 	errcode = ext2fs_bmap2(current_fs, ino, 0, 0, 0, blk, 0, &pblk);
   2107 	if (errcode) {
   2108 		com_err(argv[0], errcode,
   2109 			"while mapping logical block %llu\n", blk);
   2110 		return;
   2111 	}
   2112 	printf("%llu\n", pblk);
   2113 }
   2114 
   2115 void do_imap(int argc, char *argv[])
   2116 {
   2117 	ext2_ino_t	ino;
   2118 	unsigned long 	group, block, block_nr, offset;
   2119 
   2120 	if (common_args_process(argc, argv, 2, 2, argv[0],
   2121 				"<file>", 0))
   2122 		return;
   2123 	ino = string_to_inode(argv[1]);
   2124 	if (!ino)
   2125 		return;
   2126 
   2127 	group = (ino - 1) / EXT2_INODES_PER_GROUP(current_fs->super);
   2128 	offset = ((ino - 1) % EXT2_INODES_PER_GROUP(current_fs->super)) *
   2129 		EXT2_INODE_SIZE(current_fs->super);
   2130 	block = offset >> EXT2_BLOCK_SIZE_BITS(current_fs->super);
   2131 	if (!ext2fs_inode_table_loc(current_fs, (unsigned)group)) {
   2132 		com_err(argv[0], 0, "Inode table for group %lu is missing\n",
   2133 			group);
   2134 		return;
   2135 	}
   2136 	block_nr = ext2fs_inode_table_loc(current_fs, (unsigned)group) +
   2137 		block;
   2138 	offset &= (EXT2_BLOCK_SIZE(current_fs->super) - 1);
   2139 
   2140 	printf("Inode %d is part of block group %lu\n"
   2141 	       "\tlocated at block %lu, offset 0x%04lx\n", ino, group,
   2142 	       block_nr, offset);
   2143 
   2144 }
   2145 
   2146 #ifndef READ_ONLY
   2147 void do_set_current_time(int argc, char *argv[])
   2148 {
   2149 	time_t now;
   2150 
   2151 	if (common_args_process(argc, argv, 2, 2, argv[0],
   2152 				"<time>", 0))
   2153 		return;
   2154 
   2155 	now = string_to_time(argv[1]);
   2156 	if (now == ((time_t) -1)) {
   2157 		com_err(argv[0], 0, "Couldn't parse argument as a time: %s\n",
   2158 			argv[1]);
   2159 		return;
   2160 
   2161 	} else {
   2162 		printf("Setting current time to %s\n", time_to_string(now));
   2163 		current_fs->now = now;
   2164 	}
   2165 }
   2166 #endif /* READ_ONLY */
   2167 
   2168 static int find_supp_feature(__u32 *supp, int feature_type, char *name)
   2169 {
   2170 	int compat, bit, ret;
   2171 	unsigned int feature_mask;
   2172 
   2173 	if (name) {
   2174 		if (feature_type == E2P_FS_FEATURE)
   2175 			ret = e2p_string2feature(name, &compat, &feature_mask);
   2176 		else
   2177 			ret = e2p_jrnl_string2feature(name, &compat,
   2178 						      &feature_mask);
   2179 		if (ret)
   2180 			return ret;
   2181 
   2182 		if (!(supp[compat] & feature_mask))
   2183 			return 1;
   2184 	} else {
   2185 	        for (compat = 0; compat < 3; compat++) {
   2186 		        for (bit = 0, feature_mask = 1; bit < 32;
   2187 			     bit++, feature_mask <<= 1) {
   2188 			        if (supp[compat] & feature_mask) {
   2189 					if (feature_type == E2P_FS_FEATURE)
   2190 						fprintf(stdout, " %s",
   2191 						e2p_feature2string(compat,
   2192 						feature_mask));
   2193 					else
   2194 						fprintf(stdout, " %s",
   2195 						e2p_jrnl_feature2string(compat,
   2196 						feature_mask));
   2197 				}
   2198 	        	}
   2199 		}
   2200 	        fprintf(stdout, "\n");
   2201 	}
   2202 
   2203 	return 0;
   2204 }
   2205 
   2206 void do_supported_features(int argc, char *argv[])
   2207 {
   2208         int	ret;
   2209 	__u32	supp[3] = { EXT2_LIB_FEATURE_COMPAT_SUPP,
   2210 			    EXT2_LIB_FEATURE_INCOMPAT_SUPP,
   2211 			    EXT2_LIB_FEATURE_RO_COMPAT_SUPP };
   2212 	__u32	jrnl_supp[3] = { JFS_KNOWN_COMPAT_FEATURES,
   2213 				 JFS_KNOWN_INCOMPAT_FEATURES,
   2214 				 JFS_KNOWN_ROCOMPAT_FEATURES };
   2215 
   2216 	if (argc > 1) {
   2217 		ret = find_supp_feature(supp, E2P_FS_FEATURE, argv[1]);
   2218 		if (ret) {
   2219 			ret = find_supp_feature(jrnl_supp, E2P_JOURNAL_FEATURE,
   2220 						argv[1]);
   2221 		}
   2222 		if (ret)
   2223 			com_err(argv[0], 0, "Unknown feature: %s\n", argv[1]);
   2224 		else
   2225 			fprintf(stdout, "Supported feature: %s\n", argv[1]);
   2226 	} else {
   2227 		fprintf(stdout, "Supported features:");
   2228 		ret = find_supp_feature(supp, E2P_FS_FEATURE, NULL);
   2229 		ret = find_supp_feature(jrnl_supp, E2P_JOURNAL_FEATURE, NULL);
   2230 	}
   2231 }
   2232 
   2233 #ifndef READ_ONLY
   2234 void do_punch(int argc, char *argv[])
   2235 {
   2236 	ext2_ino_t	ino;
   2237 	blk64_t		start, end;
   2238 	int		err;
   2239 	errcode_t	errcode;
   2240 
   2241 	if (common_args_process(argc, argv, 3, 4, argv[0],
   2242 				"<file> start_blk [end_blk]",
   2243 				CHECK_FS_RW | CHECK_FS_BITMAPS))
   2244 		return;
   2245 
   2246 	ino = string_to_inode(argv[1]);
   2247 	if (!ino)
   2248 		return;
   2249 	err = strtoblk(argv[0], argv[2], &start);
   2250 	if (err)
   2251 		return;
   2252 	if (argc == 4) {
   2253 		err = strtoblk(argv[0], argv[3], &end);
   2254 		if (err)
   2255 			return;
   2256 	} else
   2257 		end = ~0;
   2258 
   2259 	errcode = ext2fs_punch(current_fs, ino, 0, 0, start, end);
   2260 
   2261 	if (errcode) {
   2262 		com_err(argv[0], errcode,
   2263 			"while truncating inode %u from %llu to %llu\n", ino,
   2264 			(unsigned long long) start, (unsigned long long) end);
   2265 		return;
   2266 	}
   2267 }
   2268 #endif /* READ_ONLY */
   2269 
   2270 void do_symlink(int argc, char *argv[])
   2271 {
   2272 	char		*cp;
   2273 	ext2_ino_t	parent;
   2274 	char		*name, *target;
   2275 	errcode_t	retval;
   2276 
   2277 	if (common_args_process(argc, argv, 3, 3, "symlink",
   2278 				"<filename> <target>", CHECK_FS_RW))
   2279 		return;
   2280 
   2281 	cp = strrchr(argv[1], '/');
   2282 	if (cp) {
   2283 		*cp = 0;
   2284 		parent = string_to_inode(argv[1]);
   2285 		if (!parent) {
   2286 			com_err(argv[1], ENOENT, 0);
   2287 			return;
   2288 		}
   2289 		name = cp+1;
   2290 	} else {
   2291 		parent = cwd;
   2292 		name = argv[1];
   2293 	}
   2294 	target = argv[2];
   2295 
   2296 try_again:
   2297 	retval = ext2fs_symlink(current_fs, parent, 0, name, target);
   2298 	if (retval == EXT2_ET_DIR_NO_SPACE) {
   2299 		retval = ext2fs_expand_dir(current_fs, parent);
   2300 		if (retval) {
   2301 			com_err(argv[0], retval, "while expanding directory");
   2302 			return;
   2303 		}
   2304 		goto try_again;
   2305 	}
   2306 	if (retval) {
   2307 		com_err("ext2fs_symlink", retval, 0);
   2308 		return;
   2309 	}
   2310 
   2311 }
   2312 
   2313 void do_dump_mmp(int argc EXT2FS_ATTR((unused)), char *argv[])
   2314 {
   2315 	struct ext2_super_block *sb;
   2316 	struct mmp_struct *mmp_s;
   2317 	time_t t;
   2318 	errcode_t retval = 0;
   2319 
   2320 	if (check_fs_open(argv[0]))
   2321 		return;
   2322 
   2323 	sb  = current_fs->super;
   2324 
   2325 	if (current_fs->mmp_buf == NULL) {
   2326 		retval = ext2fs_get_mem(current_fs->blocksize,
   2327 					&current_fs->mmp_buf);
   2328 		if (retval) {
   2329 			com_err(argv[0], retval, "allocating MMP buffer.\n");
   2330 			return;
   2331 		}
   2332 	}
   2333 
   2334 	mmp_s = current_fs->mmp_buf;
   2335 
   2336 	retval = ext2fs_mmp_read(current_fs, current_fs->super->s_mmp_block,
   2337 				 current_fs->mmp_buf);
   2338 	if (retval) {
   2339 		com_err(argv[0], retval, "reading MMP block.\n");
   2340 		return;
   2341 	}
   2342 
   2343 	t = mmp_s->mmp_time;
   2344 	fprintf(stdout, "block_number: %llu\n", current_fs->super->s_mmp_block);
   2345 	fprintf(stdout, "update_interval: %d\n",
   2346 		current_fs->super->s_mmp_update_interval);
   2347 	fprintf(stdout, "check_interval: %d\n", mmp_s->mmp_check_interval);
   2348 	fprintf(stdout, "sequence: %08x\n", mmp_s->mmp_seq);
   2349 	fprintf(stdout, "time: %lld -- %s", mmp_s->mmp_time, ctime(&t));
   2350 	fprintf(stdout, "node_name: %s\n", mmp_s->mmp_nodename);
   2351 	fprintf(stdout, "device_name: %s\n", mmp_s->mmp_bdevname);
   2352 	fprintf(stdout, "magic: 0x%x\n", mmp_s->mmp_magic);
   2353 }
   2354 
   2355 static int source_file(const char *cmd_file, int ss_idx)
   2356 {
   2357 	FILE		*f;
   2358 	char		buf[BUFSIZ];
   2359 	char		*cp;
   2360 	int		exit_status = 0;
   2361 	int		retval;
   2362 
   2363 	if (strcmp(cmd_file, "-") == 0)
   2364 		f = stdin;
   2365 	else {
   2366 		f = fopen(cmd_file, "r");
   2367 		if (!f) {
   2368 			perror(cmd_file);
   2369 			exit(1);
   2370 		}
   2371 	}
   2372 	fflush(stdout);
   2373 	fflush(stderr);
   2374 	setbuf(stdout, NULL);
   2375 	setbuf(stderr, NULL);
   2376 	while (!feof(f)) {
   2377 		if (fgets(buf, sizeof(buf), f) == NULL)
   2378 			break;
   2379 		cp = strchr(buf, '\n');
   2380 		if (cp)
   2381 			*cp = 0;
   2382 		cp = strchr(buf, '\r');
   2383 		if (cp)
   2384 			*cp = 0;
   2385 		printf("debugfs: %s\n", buf);
   2386 		retval = ss_execute_line(ss_idx, buf);
   2387 		if (retval) {
   2388 			ss_perror(ss_idx, retval, buf);
   2389 			exit_status++;
   2390 		}
   2391 	}
   2392 	if (f != stdin)
   2393 		fclose(f);
   2394 	return exit_status;
   2395 }
   2396 
   2397 int main(int argc, char **argv)
   2398 {
   2399 	int		retval;
   2400 	const char	*usage =
   2401 		"Usage: %s [-b blocksize] [-s superblock] [-f cmd_file] "
   2402 		"[-R request] [-V] ["
   2403 #ifndef READ_ONLY
   2404 		"[-w] "
   2405 #endif
   2406 		"[-c] device]";
   2407 	int		c;
   2408 	int		open_flags = EXT2_FLAG_SOFTSUPP_FEATURES | EXT2_FLAG_64BITS;
   2409 	char		*request = 0;
   2410 	int		exit_status = 0;
   2411 	char		*cmd_file = 0;
   2412 	blk64_t		superblock = 0;
   2413 	blk64_t		blocksize = 0;
   2414 	int		catastrophic = 0;
   2415 	char		*data_filename = 0;
   2416 #ifdef READ_ONLY
   2417 	const char	*opt_string = "icR:f:b:s:Vd:D";
   2418 #else
   2419 	const char	*opt_string = "iwcR:f:b:s:Vd:D";
   2420 #endif
   2421 
   2422 	if (debug_prog_name == 0)
   2423 #ifdef READ_ONLY
   2424 		debug_prog_name = "rdebugfs";
   2425 #else
   2426 		debug_prog_name = "debugfs";
   2427 #endif
   2428 	add_error_table(&et_ext2_error_table);
   2429 	fprintf (stderr, "%s %s (%s)\n", debug_prog_name,
   2430 		 E2FSPROGS_VERSION, E2FSPROGS_DATE);
   2431 
   2432 	while ((c = getopt (argc, argv, opt_string)) != EOF) {
   2433 		switch (c) {
   2434 		case 'R':
   2435 			request = optarg;
   2436 			break;
   2437 		case 'f':
   2438 			cmd_file = optarg;
   2439 			break;
   2440 		case 'd':
   2441 			data_filename = optarg;
   2442 			break;
   2443 		case 'i':
   2444 			open_flags |= EXT2_FLAG_IMAGE_FILE;
   2445 			break;
   2446 #ifndef READ_ONLY
   2447 		case 'w':
   2448 			open_flags |= EXT2_FLAG_RW;
   2449 			break;
   2450 #endif
   2451 		case 'D':
   2452 			open_flags |= EXT2_FLAG_DIRECT_IO;
   2453 			break;
   2454 		case 'b':
   2455 			blocksize = parse_ulong(optarg, argv[0],
   2456 						"block size", 0);
   2457 			break;
   2458 		case 's':
   2459 			retval = strtoblk(argv[0], optarg, &superblock);
   2460 			if (retval)
   2461 				return 1;
   2462 			break;
   2463 		case 'c':
   2464 			catastrophic = 1;
   2465 			break;
   2466 		case 'V':
   2467 			/* Print version number and exit */
   2468 			fprintf(stderr, "\tUsing %s\n",
   2469 				error_message(EXT2_ET_BASE));
   2470 			exit(0);
   2471 		default:
   2472 			com_err(argv[0], 0, usage, debug_prog_name);
   2473 			return 1;
   2474 		}
   2475 	}
   2476 	if (optind < argc)
   2477 		open_filesystem(argv[optind], open_flags,
   2478 				superblock, blocksize, catastrophic,
   2479 				data_filename);
   2480 
   2481 	sci_idx = ss_create_invocation(debug_prog_name, "0.0", (char *) NULL,
   2482 				       &debug_cmds, &retval);
   2483 	if (retval) {
   2484 		ss_perror(sci_idx, retval, "creating invocation");
   2485 		exit(1);
   2486 	}
   2487 	ss_get_readline(sci_idx);
   2488 
   2489 	(void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval);
   2490 	if (retval) {
   2491 		ss_perror(sci_idx, retval, "adding standard requests");
   2492 		exit (1);
   2493 	}
   2494 	if (extra_cmds)
   2495 		ss_add_request_table (sci_idx, extra_cmds, 1, &retval);
   2496 	if (retval) {
   2497 		ss_perror(sci_idx, retval, "adding extra requests");
   2498 		exit (1);
   2499 	}
   2500 	if (request) {
   2501 		retval = 0;
   2502 		retval = ss_execute_line(sci_idx, request);
   2503 		if (retval) {
   2504 			ss_perror(sci_idx, retval, request);
   2505 			exit_status++;
   2506 		}
   2507 	} else if (cmd_file) {
   2508 		exit_status = source_file(cmd_file, sci_idx);
   2509 	} else {
   2510 		ss_listen(sci_idx);
   2511 	}
   2512 
   2513 	ss_delete_invocation(sci_idx);
   2514 
   2515 	if (current_fs)
   2516 		close_filesystem();
   2517 
   2518 	remove_error_table(&et_ext2_error_table);
   2519 	return exit_status;
   2520 }
   2521