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