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