blob: b0ba7c3fd1b205c032931f3a14f9d905c2156544 [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
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>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000017#ifdef HAVE_GETOPT_H
Theodore Ts'o3839e651997-04-26 13:21:57 +000018#include <getopt.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000019#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>
Theodore Ts'o3839e651997-04-26 13:21:57 +000030#include <sys/types.h>
31#include <sys/stat.h>
32
33#include "et/com_err.h"
34#include "ss/ss.h"
35#include "debugfs.h"
36
37extern ss_request_table debug_cmds;
38
39ext2_filsys fs = NULL;
40ino_t root, cwd;
41
Theodore Ts'o50e1e101997-04-26 13:58:21 +000042static void open_filesystem(char *device, int open_flags)
Theodore Ts'o3839e651997-04-26 13:21:57 +000043{
44 int retval;
45
46 retval = ext2fs_open(device, open_flags, 0, 0, unix_io_manager, &fs);
47 if (retval) {
48 com_err(device, retval, "while opening filesystem");
49 fs = NULL;
50 return;
51 }
52 retval = ext2fs_read_inode_bitmap(fs);
53 if (retval) {
54 com_err(device, retval, "while reading inode bitmap");
55 goto errout;
56 }
57 retval = ext2fs_read_block_bitmap(fs);
58 if (retval) {
59 com_err(device, retval, "while reading block bitmap");
60 goto errout;
61 }
62 root = cwd = EXT2_ROOT_INO;
63 return;
64
65errout:
66 retval = ext2fs_close(fs);
67 if (retval)
68 com_err(device, retval, "while trying to close filesystem");
69 fs = NULL;
70}
71
72void do_open_filesys(int argc, char **argv)
73{
Theodore Ts'o50e1e101997-04-26 13:58:21 +000074 const char *usage = "Usage: open [-w] <device>";
Theodore Ts'o3839e651997-04-26 13:21:57 +000075 char c;
76 int open_flags = 0;
77
Theodore Ts'o50e1e101997-04-26 13:58:21 +000078 optind = 1;
79#ifdef HAVE_OPTRESET
80 optreset = 1; /* Makes BSD getopt happy */
81#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000082 while ((c = getopt (argc, argv, "w")) != EOF) {
83 switch (c) {
84 case 'w':
85 open_flags = EXT2_FLAG_RW;
86 break;
87 default:
88 com_err(argv[0], 0, usage);
89 return;
90 }
91 }
92 if (optind != argc-1) {
93 com_err(argv[0], 0, usage);
94 return;
95 }
96 if (check_fs_not_open(argv[0]))
97 return;
98 open_filesystem(argv[optind], open_flags);
99}
100
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000101static void close_filesystem(NOARGS)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000102{
103 int retval;
104
105 if (fs->flags & EXT2_FLAG_IB_DIRTY) {
106 retval = ext2fs_write_inode_bitmap(fs);
107 if (retval)
108 com_err("ext2fs_write_inode_bitmap", retval, "");
109 }
110 if (fs->flags & EXT2_FLAG_BB_DIRTY) {
111 retval = ext2fs_write_block_bitmap(fs);
112 if (retval)
113 com_err("ext2fs_write_block_bitmap", retval, "");
114 }
115 retval = ext2fs_close(fs);
116 if (retval)
117 com_err("ext2fs_close", retval, "");
118 fs = NULL;
119 return;
120}
121
122void do_close_filesys(int argc, char **argv)
123{
124 if (argc > 1) {
125 com_err(argv[0], 0, "Usage: close_filesys");
126 return;
127 }
128 if (check_fs_open(argv[0]))
129 return;
130 close_filesystem();
131}
132
133void do_init_filesys(int argc, char **argv)
134{
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000135 const char *usage = "Usage: initialize <device> <blocksize>";
Theodore Ts'o3839e651997-04-26 13:21:57 +0000136 struct ext2_super_block param;
137 errcode_t retval;
138 char *tmp;
139
140 if (argc != 3) {
141 com_err(argv[0], 0, usage);
142 return;
143 }
144 if (check_fs_not_open(argv[0]))
145 return;
146
147 memset(&param, 0, sizeof(struct ext2_super_block));
148 param.s_blocks_count = strtoul(argv[2], &tmp, 0);
149 if (*tmp) {
150 com_err(argv[0], 0, "Bad blocks count - %s", argv[2]);
151 return;
152 }
153 retval = ext2fs_initialize(argv[1], 0, &param, unix_io_manager, &fs);
154 if (retval) {
155 com_err(argv[1], retval, "while initializing filesystem");
156 fs = NULL;
157 return;
158 }
159 root = cwd = EXT2_ROOT_INO;
160 return;
161}
162
163void do_show_super_stats(int argc, char *argv[])
164{
165 int i;
166 FILE *out;
167
168 if (argc > 1) {
169 com_err(argv[0], 0, "Usage: show_super");
170 return;
171 }
172 if (check_fs_open(argv[0]))
173 return;
174 out = open_pager();
175 fprintf(out, "Filesystem is read-%s\n", fs->flags & EXT2_FLAG_RW ?
176 "write" : "only");
177 fprintf(out, "Last mount time = %s", ctime(&fs->super->s_mtime));
178 fprintf(out, "Last write time = %s", ctime(&fs->super->s_wtime));
179 fprintf(out, "Mount counts = %d (maximal = %d)\n",
180 fs->super->s_mnt_count, fs->super->s_max_mnt_count);
181 fprintf(out, "Superblock size = %d\n", sizeof(struct ext2_super_block));
182 fprintf(out, "Block size = %d, fragment size = %d\n",
183 EXT2_BLOCK_SIZE(fs->super), EXT2_FRAG_SIZE(fs->super));
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000184 fprintf(out, "%d inodes, %d free\n", fs->super->s_inodes_count,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000185 fs->super->s_free_inodes_count);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000186 fprintf(out, "%d blocks, %d free, %d reserved, first block = %d\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000187 fs->super->s_blocks_count, fs->super->s_free_blocks_count,
188 fs->super->s_r_blocks_count, fs->super->s_first_data_block);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000189 fprintf(out, "%d blocks per group\n", fs->super->s_blocks_per_group);
190 fprintf(out, "%d fragments per group\n", fs->super->s_frags_per_group);
191 fprintf(out, "%d inodes per group\n", EXT2_INODES_PER_GROUP(fs->super));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000192 fprintf(out, "%d inodes per block\n", EXT2_INODES_PER_BLOCK(fs->super));
193 fprintf(out, "%ld group%s (%ld descriptors block%s)\n",
194 fs->group_desc_count, (fs->group_desc_count != 1) ? "s" : "",
195 fs->desc_blocks, (fs->desc_blocks != 1) ? "s" : "");
196 for (i = 0; i < fs->group_desc_count; i++)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000197 fprintf(out, " Group %2d: block bitmap at %d, "
198 "inode bitmap at %d, "
199 "inode table at %d\n"
Theodore Ts'o3839e651997-04-26 13:21:57 +0000200 " %d free block%s, "
201 "%d free inode%s, "
202 "%d used director%s\n",
203 i, fs->group_desc[i].bg_block_bitmap,
204 fs->group_desc[i].bg_inode_bitmap,
205 fs->group_desc[i].bg_inode_table,
206 fs->group_desc[i].bg_free_blocks_count,
207 fs->group_desc[i].bg_free_blocks_count != 1 ? "s" : "",
208 fs->group_desc[i].bg_free_inodes_count,
209 fs->group_desc[i].bg_free_inodes_count != 1 ? "s" : "",
210 fs->group_desc[i].bg_used_dirs_count,
211 fs->group_desc[i].bg_used_dirs_count != 1 ? "ies" : "y");
212 close_pager(out);
213}
214
215struct list_blocks_struct {
216 FILE *f;
217 int total;
218};
219
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000220static int list_blocks_proc(ext2_filsys fs, blk_t *blocknr, int blockcnt,
221 void *private)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000222{
223 struct list_blocks_struct *lb = (struct list_blocks_struct *) private;
224
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000225 fprintf(lb->f, "%d ", *blocknr);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000226 lb->total++;
227 return 0;
228}
229
230
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000231static void dump_blocks(FILE *f, ino_t inode)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000232{
233 struct list_blocks_struct lb;
234
235 fprintf(f, "BLOCKS:\n");
236 lb.total = 0;
237 lb.f = f;
238 ext2fs_block_iterate(fs,inode,0,NULL,list_blocks_proc,(void *)&lb);
239 if (lb.total)
240 fprintf(f, "\nTOTAL: %d\n", lb.total);
241 fprintf(f,"\n");
242}
243
244
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000245static void dump_inode(ino_t inode_num, struct ext2_inode inode)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000246{
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000247 const char *i_type;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000248 FILE *out;
249
250 out = open_pager();
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000251 if (LINUX_S_ISDIR(inode.i_mode)) i_type = "directory";
252 else if (LINUX_S_ISREG(inode.i_mode)) i_type = "regular";
253 else if (LINUX_S_ISLNK(inode.i_mode)) i_type = "symlink";
254 else if (LINUX_S_ISBLK(inode.i_mode)) i_type = "block special";
255 else if (LINUX_S_ISCHR(inode.i_mode)) i_type = "character special";
256 else if (LINUX_S_ISFIFO(inode.i_mode)) i_type = "FIFO";
257 else if (LINUX_S_ISSOCK(inode.i_mode)) i_type = "socket";
Theodore Ts'o3839e651997-04-26 13:21:57 +0000258 else i_type = "bad type";
259 fprintf(out, "Inode: %ld Type: %s ", inode_num, i_type);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000260 fprintf(out, "Mode: %04o Flags: 0x%x Version: %d\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000261 inode.i_mode & 0777, inode.i_flags, inode.i_version);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000262 fprintf(out, "User: %5d Group: %5d Size: %d\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000263 inode.i_uid, inode.i_gid, inode.i_size);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000264 fprintf(out, "File ACL: %d Directory ACL: %d\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000265 inode.i_file_acl, inode.i_dir_acl);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000266 fprintf(out, "Links: %d Blockcount: %d\n", inode.i_links_count,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000267 inode.i_blocks);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000268#if HAVE_EXT2_FRAGS
269 fprintf(out, "Fragment: Address: %d Number: %d Size: %d\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000270 inode.i_faddr, inode.i_frag, inode.i_fsize);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000271#endif
272 fprintf(out, "ctime: 0x%08x -- %s", inode.i_ctime,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000273 ctime(&inode.i_ctime));
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000274 fprintf(out, "atime: 0x%08x -- %s", inode.i_atime,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000275 ctime(&inode.i_atime));
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000276 fprintf(out, "mtime: 0x%08x -- %s", inode.i_mtime,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000277 ctime(&inode.i_mtime));
278 if (inode.i_dtime)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000279 fprintf(out, "dtime: 0x%08x -- %s", inode.i_dtime,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000280 ctime(&inode.i_dtime));
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000281 if (LINUX_S_ISLNK(inode.i_mode) && inode.i_blocks == 0)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000282 fprintf(out, "Fast_link_dest: %s\n", (char *)inode.i_block);
283 else
284 dump_blocks(out, inode_num);
285 close_pager(out);
286}
287
288
289void do_stat(int argc, char *argv[])
290{
291 ino_t inode;
292 struct ext2_inode inode_buf;
293 int retval;
294
295 if (argc != 2) {
296 com_err(argv[0], 0, "Usage: stat <file>");
297 return;
298 }
299 if (check_fs_open(argv[0]))
300 return;
301 inode = string_to_inode(argv[1]);
302 if (!inode)
303 return;
304
305 retval = ext2fs_read_inode(fs,inode,&inode_buf);
306 if (retval)
307 {
308 com_err(argv[0], 0, "Reading inode");
309 return;
310 }
311
312 dump_inode(inode,inode_buf);
313 return;
314}
315
316void do_chroot(int argc, char *argv[])
317{
318 ino_t inode;
319 int retval;
320
321 if (argc != 2) {
322 com_err(argv[0], 0, "Usage: chroot <file>");
323 return;
324 }
325 if (check_fs_open(argv[0]))
326 return;
327 inode = string_to_inode(argv[1]);
328 if (!inode)
329 return;
330
331 retval = ext2fs_check_directory(fs, inode);
332 if (retval) {
333 com_err(argv[1], retval, "");
334 return;
335 }
336 root = inode;
337}
338
339void do_clri(int argc, char *argv[])
340{
341 ino_t inode;
342 int retval;
343 struct ext2_inode inode_buf;
344
345 if (argc != 2) {
346 com_err(argv[0], 0, "Usage: clri <file>");
347 return;
348 }
349 if (check_fs_open(argv[0]))
350 return;
351 if (!(fs->flags & EXT2_FLAG_RW)) {
352 com_err(argv[0], 0, "Filesystem opened read/only");
353 return;
354 }
355 inode = string_to_inode(argv[1]);
356 if (!inode)
357 return;
358
359 retval = ext2fs_read_inode(fs, inode, &inode_buf);
360 if (retval) {
361 com_err(argv[0], 0, "while trying to read inode %d", inode);
362 return;
363 }
364 memset(&inode_buf, 0, sizeof(inode_buf));
365 retval = ext2fs_write_inode(fs, inode, &inode_buf);
366 if (retval) {
367 com_err(argv[0], retval, "while trying to write inode %d",
368 inode);
369 return;
370 }
371}
372
373void do_freei(int argc, char *argv[])
374{
375 ino_t inode;
376
377 if (argc != 2) {
378 com_err(argv[0], 0, "Usage: freei <file>");
379 return;
380 }
381 if (check_fs_open(argv[0]))
382 return;
383 if (!(fs->flags & EXT2_FLAG_RW)) {
384 com_err(argv[0], 0, "Filesystem opened read/only");
385 return;
386 }
387 inode = string_to_inode(argv[1]);
388 if (!inode)
389 return;
390
Theodore Ts'of3db3561997-04-26 13:34:30 +0000391 if (!ext2fs_test_inode_bitmap(fs->inode_map,inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000392 com_err(argv[0], 0, "Warning: inode already clear");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000393 ext2fs_unmark_inode_bitmap(fs->inode_map,inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000394 ext2fs_mark_ib_dirty(fs);
395}
396
397void do_seti(int argc, char *argv[])
398{
399 ino_t inode;
400
401 if (argc != 2) {
402 com_err(argv[0], 0, "Usage: seti <file>");
403 return;
404 }
405 if (check_fs_open(argv[0]))
406 return;
407 if (!(fs->flags & EXT2_FLAG_RW)) {
408 com_err(argv[0], 0, "Filesystem opened read/only");
409 return;
410 }
411 inode = string_to_inode(argv[1]);
412 if (!inode)
413 return;
414
Theodore Ts'of3db3561997-04-26 13:34:30 +0000415 if (ext2fs_test_inode_bitmap(fs->inode_map,inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000416 com_err(argv[0], 0, "Warning: inode already set");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000417 ext2fs_mark_inode_bitmap(fs->inode_map,inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000418 ext2fs_mark_ib_dirty(fs);
419}
420
421void do_testi(int argc, char *argv[])
422{
423 ino_t inode;
424
425 if (argc != 2) {
426 com_err(argv[0], 0, "Usage: testi <file>");
427 return;
428 }
429 if (check_fs_open(argv[0]))
430 return;
431 inode = string_to_inode(argv[1]);
432 if (!inode)
433 return;
434
Theodore Ts'of3db3561997-04-26 13:34:30 +0000435 if (ext2fs_test_inode_bitmap(fs->inode_map,inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000436 printf("Inode %ld is marked in use\n", inode);
437 else
438 printf("Inode %ld is not in use\n", inode);
439}
440
441
442void do_freeb(int argc, char *argv[])
443{
444 blk_t block;
445 char *tmp;
446
447 if (argc != 2) {
448 com_err(argv[0], 0, "Usage: freeb <block>");
449 return;
450 }
451 if (check_fs_open(argv[0]))
452 return;
453 if (!(fs->flags & EXT2_FLAG_RW)) {
454 com_err(argv[0], 0, "Filesystem opened read/only");
455 return;
456 }
457 block = strtoul(argv[1], &tmp, 0);
458 if (!block || *tmp) {
459 com_err(argv[0], 0, "No block 0");
460 return;
461 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000462 if (!ext2fs_test_block_bitmap(fs->block_map,block))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000463 com_err(argv[0], 0, "Warning: block already clear");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000464 ext2fs_unmark_block_bitmap(fs->block_map,block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000465 ext2fs_mark_bb_dirty(fs);
466}
467
468void do_setb(int argc, char *argv[])
469{
470 blk_t block;
471 char *tmp;
472
473 if (argc != 2) {
474 com_err(argv[0], 0, "Usage: setb <block>");
475 return;
476 }
477 if (check_fs_open(argv[0]))
478 return;
479 if (!(fs->flags & EXT2_FLAG_RW)) {
480 com_err(argv[0], 0, "Filesystem opened read/only");
481 return;
482 }
483 block = strtoul(argv[1], &tmp, 0);
484 if (!block || *tmp) {
485 com_err(argv[0], 0, "No block 0");
486 return;
487 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000488 if (ext2fs_test_block_bitmap(fs->block_map,block))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000489 com_err(argv[0], 0, "Warning: block already set");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000490 ext2fs_mark_block_bitmap(fs->block_map,block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000491 ext2fs_mark_bb_dirty(fs);
492}
493
494void do_testb(int argc, char *argv[])
495{
496 blk_t block;
497 char *tmp;
498
499 if (argc != 2) {
500 com_err(argv[0], 0, "Usage: testb <block>");
501 return;
502 }
503 if (check_fs_open(argv[0]))
504 return;
505 block = strtoul(argv[1], &tmp, 0);
506 if (!block || *tmp) {
507 com_err(argv[0], 0, "No block 0");
508 return;
509 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000510 if (ext2fs_test_block_bitmap(fs->block_map,block))
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000511 printf("Block %d marked in use\n", block);
512 else printf("Block %d not in use\n", block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000513}
514
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000515static void modify_u8(char *com, const char *prompt,
516 const char *format, __u8 *val)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000517{
518 char buf[200];
519 u_char v;
520 char *tmp;
521
522 sprintf(buf, format, *val);
523 printf("%30s [%s] ", prompt, buf);
524 fgets(buf, sizeof(buf), stdin);
525 if (buf[strlen (buf) - 1] == '\n')
526 buf[strlen (buf) - 1] = '\0';
527 if (!buf[0])
528 return;
529 v = strtol(buf, &tmp, 0);
530 if (*tmp)
531 com_err(com, 0, "Bad value - %s", buf);
532 else
533 *val = v;
534}
535
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000536static void modify_u16(char *com, const char *prompt,
537 const char *format, __u16 *val)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000538{
539 char buf[200];
540 u_short v;
541 char *tmp;
542
543 sprintf(buf, format, *val);
544 printf("%30s [%s] ", prompt, buf);
545 fgets(buf, sizeof(buf), stdin);
546 if (buf[strlen (buf) - 1] == '\n')
547 buf[strlen (buf) - 1] = '\0';
548 if (!buf[0])
549 return;
550 v = strtol(buf, &tmp, 0);
551 if (*tmp)
552 com_err(com, 0, "Bad value - %s", buf);
553 else
554 *val = v;
555}
556
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000557static void modify_u32(char *com, const char *prompt,
558 const char *format, __u32 *val)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000559{
560 char buf[200];
561 u_long v;
562 char *tmp;
563
564 sprintf(buf, format, *val);
565 printf("%30s [%s] ", prompt, buf);
566 fgets(buf, sizeof(buf), stdin);
567 if (buf[strlen (buf) - 1] == '\n')
568 buf[strlen (buf) - 1] = '\0';
569 if (!buf[0])
570 return;
571 v = strtol(buf, &tmp, 0);
572 if (*tmp)
573 com_err(com, 0, "Bad value - %s", buf);
574 else
575 *val = v;
576}
577
578
579void do_modify_inode(int argc, char *argv[])
580{
581 struct ext2_inode inode;
582 ino_t inode_num;
583 int i;
584 errcode_t retval;
585 char buf[80];
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000586 const char *hex_format = "0x%x";
587 const char *octal_format = "0%o";
588 const char *decimal_format = "%d";
Theodore Ts'o3839e651997-04-26 13:21:57 +0000589
590 if (argc != 2) {
591 com_err(argv[0], 0, "Usage: modify_inode <file>");
592 return;
593 }
594 if (check_fs_open(argv[0]))
595 return;
596 if (!(fs->flags & EXT2_FLAG_RW)) {
597 com_err(argv[0], 0, "Filesystem opened read/only");
598 return;
599 }
600
601 inode_num = string_to_inode(argv[1]);
602 if (!inode_num)
603 return;
604
605 retval = ext2fs_read_inode(fs, inode_num, &inode);
606 if (retval) {
607 com_err(argv[1], retval, "while trying to read inode %d",
608 inode_num);
609 return;
610 }
611
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000612 modify_u16(argv[0], "Mode", octal_format, &inode.i_mode);
613 modify_u16(argv[0], "User ID", decimal_format, &inode.i_uid);
614 modify_u16(argv[0], "Group ID", decimal_format, &inode.i_gid);
615 modify_u32(argv[0], "Size", decimal_format, &inode.i_size);
616 modify_u32(argv[0], "Creation time", decimal_format, &inode.i_ctime);
617 modify_u32(argv[0], "Modification time", decimal_format, &inode.i_mtime);
618 modify_u32(argv[0], "Access time", decimal_format, &inode.i_atime);
619 modify_u32(argv[0], "Deletion time", decimal_format, &inode.i_dtime);
620 modify_u16(argv[0], "Link count", decimal_format, &inode.i_links_count);
621 modify_u32(argv[0], "Block count", decimal_format, &inode.i_blocks);
622 modify_u32(argv[0], "File flags", hex_format, &inode.i_flags);
623#if 0
624 modify_u32(argv[0], "Reserved1", decimal_format, &inode.i_reserved1);
625#endif
626 modify_u32(argv[0], "File acl", decimal_format, &inode.i_file_acl);
627 modify_u32(argv[0], "Directory acl", decimal_format, &inode.i_dir_acl);
628 modify_u32(argv[0], "Fragment address", decimal_format, &inode.i_faddr);
629#if HAVE_EXT2_FRAGS
630 modify_u8(argv[0], "Fragment number", decimal_format, &inode.i_frag);
631 modify_u8(argv[0], "Fragment size", decimal_format, &inode.i_fsize);
632#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000633 for (i=0; i < EXT2_NDIR_BLOCKS; i++) {
634 sprintf(buf, "Direct Block #%d", i);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000635 modify_u32(argv[0], buf, decimal_format, &inode.i_block[i]);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000636 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000637 modify_u32(argv[0], "Indirect Block", decimal_format,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000638 &inode.i_block[EXT2_IND_BLOCK]);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000639 modify_u32(argv[0], "Double Indirect Block", decimal_format,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000640 &inode.i_block[EXT2_DIND_BLOCK]);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000641 modify_u32(argv[0], "Triple Indirect Block", decimal_format,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000642 &inode.i_block[EXT2_TIND_BLOCK]);
643 retval = ext2fs_write_inode(fs, inode_num, &inode);
644 if (retval) {
645 com_err(argv[1], retval, "while trying to write inode %d",
646 inode_num);
647 return;
648 }
649}
650
651/*
652 * list directory
653 */
654
655struct list_dir_struct {
656 FILE *f;
657 int col;
658};
659
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000660static int list_dir_proc(struct ext2_dir_entry *dirent,
661 int offset,
662 int blocksize,
663 char *buf,
664 void *private)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000665{
666 char name[EXT2_NAME_LEN];
667 char tmp[EXT2_NAME_LEN + 16];
668
669 struct list_dir_struct *ls = (struct list_dir_struct *) private;
670 int thislen;
671
672 thislen = (dirent->name_len < EXT2_NAME_LEN) ? dirent->name_len :
673 EXT2_NAME_LEN;
674 strncpy(name, dirent->name, thislen);
675 name[thislen] = '\0';
676
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000677 sprintf(tmp, "%d (%d) %s ", dirent->inode, dirent->rec_len, name);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000678 thislen = strlen(tmp);
679
680 if (ls->col + thislen > 80) {
681 fprintf(ls->f, "\n");
682 ls->col = 0;
683 }
684 fprintf(ls->f, "%s", tmp);
685 ls->col += thislen;
686
687 return 0;
688}
689
690void do_list_dir(int argc, char *argv[])
691{
692 ino_t inode;
693 int retval;
694 struct list_dir_struct ls;
695
696 if (argc > 2) {
697 com_err(argv[0], 0, "Usage: list_dir [pathname]");
698 return;
699 }
700 if (check_fs_open(argv[0]))
701 return;
702
703 if (argc == 2)
704 inode = string_to_inode(argv[1]);
705 else
706 inode = cwd;
707 if (!inode)
708 return;
709
710 ls.f = open_pager();
711 ls.col = 0;
712 retval = ext2fs_dir_iterate(fs, inode, DIRENT_FLAG_INCLUDE_EMPTY,
713 0, list_dir_proc, &ls);
714 fprintf(ls.f, "\n");
715 close_pager(ls.f);
716 if (retval)
717 com_err(argv[1], retval, "");
718
719 return;
720}
721
722void do_change_working_dir(int argc, char *argv[])
723{
724 ino_t inode;
725 int retval;
726
727 if (argc != 2) {
728 com_err(argv[0], 0, "Usage: cd <file>");
729 return;
730 }
731 if (check_fs_open(argv[0]))
732 return;
733
734 inode = string_to_inode(argv[1]);
735 if (!inode)
736 return;
737
738 retval = ext2fs_check_directory(fs, inode);
739 if (retval) {
740 com_err(argv[1], retval, "");
741 return;
742 }
743 cwd = inode;
744 return;
745}
746
Theodore Ts'o3839e651997-04-26 13:21:57 +0000747void do_print_working_directory(int argc, char *argv[])
748{
749 int retval;
750 char *pathname = NULL;
751
752 if (argc > 1) {
753 com_err(argv[0], 0, "Usage: print_working_directory");
754 return;
755 }
756 if (check_fs_open(argv[0]))
757 return;
758
759 retval = ext2fs_get_pathname(fs, cwd, 0, &pathname);
760 if (retval) {
761 com_err(argv[0], retval,
762 "while trying to get pathname of cwd");
763 }
764 printf("[pwd] INODE: %6ld PATH: %s\n", cwd, pathname);
765 free(pathname);
766 retval = ext2fs_get_pathname(fs, root, 0, &pathname);
767 if (retval) {
768 com_err(argv[0], retval,
769 "while trying to get pathname of root");
770 }
771 printf("[root] INODE: %6ld PATH: %s\n", root, pathname);
772 free(pathname);
773 return;
774}
775
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000776static void make_link(char *sourcename, char *destname)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000777{
778 ino_t inode;
779 int retval;
780 ino_t dir;
781 char *dest, *cp, *basename;
782
783 /*
784 * Get the source inode
785 */
786 inode = string_to_inode(sourcename);
787 if (!inode)
788 return;
789 basename = strrchr(sourcename, '/');
790 if (basename)
791 basename++;
792 else
793 basename = sourcename;
794 /*
795 * Figure out the destination. First see if it exists and is
796 * a directory.
797 */
798 if (! (retval=ext2fs_namei(fs, root, cwd, destname, &dir)))
799 dest = basename;
800 else {
801 /*
802 * OK, it doesn't exist. See if it is
803 * '<dir>/basename' or 'basename'
804 */
805 cp = strrchr(destname, '/');
806 if (cp) {
807 *cp = 0;
808 dir = string_to_inode(destname);
809 if (!dir)
810 return;
811 dest = cp+1;
812 } else {
813 dir = cwd;
814 dest = destname;
815 }
816 }
817
818 retval = ext2fs_link(fs, dir, dest, inode, 0);
819 if (retval)
820 com_err("make_link", retval, "");
821 return;
822}
823
824
825void do_link(int argc, char *argv[])
826{
827 if (argc != 3) {
828 com_err(argv[0], 0, "Usage: link <source_file> <dest_name>");
829 return;
830 }
831 if (check_fs_open(argv[0]))
832 return;
833
834 make_link(argv[1], argv[2]);
835}
836
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000837static void unlink_file_by_name(char *filename)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000838{
839 int retval;
840 ino_t dir;
841 char *basename;
842
843 basename = strrchr(filename, '/');
844 if (basename) {
845 *basename++ = '0';
846 dir = string_to_inode(filename);
847 if (!dir)
848 return;
849 } else {
850 dir = cwd;
851 basename = filename;
852 }
853 retval = ext2fs_unlink(fs, dir, basename, 0, 0);
854 if (retval)
855 com_err("unlink_file_by_name", retval, "");
856 return;
857}
858
859void do_unlink(int argc, char *argv[])
860{
861 if (argc != 2) {
862 com_err(argv[0], 0, "Usage: unlink <pathname>");
863 return;
864 }
865 if (check_fs_open(argv[0]))
866 return;
867
868 unlink_file_by_name(argv[1]);
869}
870
871void do_find_free_block(int argc, char *argv[])
872{
873 blk_t free_blk, goal;
874 errcode_t retval;
875 char *tmp;
876
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000877 if ((argc > 2) || (argc==2 && *argv[1] == '?')) {
878 com_err(argv[0], 0, "Usage: find_free_block [goal]");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000879 return;
880 }
881 if (check_fs_open(argv[0]))
882 return;
883
884 if (argc > 1) {
885 goal = strtol(argv[1], &tmp, 0);
886 if (*tmp) {
887 com_err(argv[0], 0, "Bad goal - %s", argv[1]);
888 return;
889 }
890 }
891 else
892 goal = fs->super->s_first_data_block;
893
894 retval = ext2fs_new_block(fs, goal, 0, &free_blk);
895 if (retval)
896 com_err("ext2fs_new_block", retval, "");
897 else
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000898 printf("Free block found: %d\n", free_blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000899
900}
901
902void do_find_free_inode(int argc, char *argv[])
903{
904 ino_t free_inode, dir;
905 int mode;
906 int retval;
907 char *tmp;
908
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000909 if (argc > 3 || (argc>1 && *argv[1] == '?')) {
910 com_err(argv[0], 0, "Usage: find_free_inode [dir] [mode]");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000911 return;
912 }
913 if (check_fs_open(argv[0]))
914 return;
915
916 if (argc > 1) {
917 dir = strtol(argv[1], &tmp, 0);
918 if (*tmp) {
919 com_err(argv[0], 0, "Bad dir - %s", argv[1]);
920 return;
921 }
922 }
923 else
924 dir = root;
925 if (argc > 2) {
926 mode = strtol(argv[2], &tmp, 0);
927 if (*tmp) {
928 com_err(argv[0], 0, "Bad mode - %s", argv[2]);
929 return;
930 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000931 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000932 mode = 010755;
933
934 retval = ext2fs_new_inode(fs, dir, mode, 0, &free_inode);
935 if (retval)
936 com_err("ext2fs_new_inode", retval, "");
937 else
938 printf("Free inode found: %ld\n", free_inode);
939}
940
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000941struct copy_file_struct {
942 unsigned long size;
943 int done, fd, blocks;
944 errcode_t err;
945};
946
947static int copy_file_proc(ext2_filsys fs,
948 blk_t *blocknr,
949 int blockcnt,
950 void *private)
951{
952 struct copy_file_struct *cs = (struct copy_file_struct *) private;
953 blk_t new_blk;
954 static blk_t last_blk = 0;
955 char *block;
956 errcode_t retval;
957 int group;
958 int nr;
959
960 if (*blocknr) {
961 new_blk = *blocknr;
962 } else {
963 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
964 if (retval) {
965 cs->err = retval;
966 return BLOCK_ABORT;
967 }
968 }
969 last_blk = new_blk;
970 block = malloc(fs->blocksize);
971 if (!block) {
972 cs->err = ENOMEM;
973 return BLOCK_ABORT;
974 }
975 if (blockcnt >= 0) {
976 nr = read(cs->fd, block, fs->blocksize);
977 } else {
978 nr = fs->blocksize;
979 memset(block, 0, nr);
980 }
981 if (nr == 0) {
982 cs->done = 1;
983 return BLOCK_ABORT;
984 }
985 if (nr < 0) {
986 cs->err = nr;
987 return BLOCK_ABORT;
988 }
989 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
990 if (retval) {
991 cs->err = retval;
992 return BLOCK_ABORT;
993 }
994 free(block);
995 if (blockcnt >= 0)
996 cs->size += nr;
997 cs->blocks += fs->blocksize / 512;
998 printf("%ld(%d) ", cs->size, blockcnt);
999 fflush(stdout);
1000 if (nr < fs->blocksize) {
1001 cs->done = 1;
1002 printf("\n");
1003 }
1004 *blocknr = new_blk;
1005 ext2fs_mark_block_bitmap(fs->block_map, new_blk);
1006 ext2fs_mark_bb_dirty(fs);
1007 group = ext2fs_group_of_blk(fs, new_blk);
1008 fs->group_desc[group].bg_free_blocks_count--;
1009 fs->super->s_free_blocks_count--;
1010 ext2fs_mark_super_dirty(fs);
1011 if (cs->done)
1012 return (BLOCK_CHANGED | BLOCK_ABORT);
1013 else
1014 return BLOCK_CHANGED;
1015}
1016
1017static errcode_t copy_file(int fd, ino_t newfile)
1018{
1019 errcode_t retval;
1020 struct copy_file_struct cs;
1021 struct ext2_inode inode;
1022
1023 cs.fd = fd;
1024 cs.done = 0;
1025 cs.err = 0;
1026 cs.size = 0;
1027 cs.blocks = 0;
1028
1029 retval = ext2fs_block_iterate(fs, newfile, BLOCK_FLAG_APPEND,
1030 0, copy_file_proc, &cs);
1031
1032 if (cs.err)
1033 return cs.err;
1034 if (!cs.done)
1035 return EXT2_ET_EXPAND_DIR_ERR;
1036
1037 /*
1038 * Update the size and block count fields in the inode.
1039 */
1040 retval = ext2fs_read_inode(fs, newfile, &inode);
1041 if (retval)
1042 return retval;
1043
1044 inode.i_blocks += cs.blocks;
1045
1046 retval = ext2fs_write_inode(fs, newfile, &inode);
1047 if (retval)
1048 return retval;
1049
1050 return 0;
1051}
1052
1053void do_write(int argc, char *argv[])
1054{
1055 int fd;
1056 struct stat statbuf;
1057 ino_t newfile;
1058 errcode_t retval;
1059 struct ext2_inode inode;
1060
1061 if (check_fs_open(argv[0]))
1062 return;
1063 if (argc != 3) {
1064 com_err(argv[0], 0, "Usage: write <nativefile> <newfile>");
1065 return;
1066 }
1067 if (!(fs->flags & EXT2_FLAG_RW)) {
1068 com_err(argv[0], 0, "read-only filesystem");
1069 return;
1070 }
1071 fd = open(argv[1], O_RDONLY);
1072 if (fd < 0) {
1073 com_err(argv[1], fd, "");
1074 return;
1075 }
1076 if (fstat(fd, &statbuf) < 0) {
1077 com_err(argv[1], errno, "");
1078 close(fd);
1079 return;
1080 }
1081
1082 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
1083 if (retval) {
1084 com_err(argv[0], retval, "");
1085 close(fd);
1086 return;
1087 }
1088 printf("Allocated inode: %ld\n", newfile);
1089 retval = ext2fs_link(fs, cwd, argv[2], newfile, 0);
1090 if (retval) {
1091 com_err(argv[2], retval, "");
1092 close(fd);
1093 return;
1094 }
1095 if (ext2fs_test_inode_bitmap(fs->inode_map,newfile))
1096 com_err(argv[0], 0, "Warning: inode already set");
1097 ext2fs_mark_inode_bitmap(fs->inode_map,newfile);
1098 ext2fs_mark_ib_dirty(fs);
1099 memset(&inode, 0, sizeof(inode));
1100 inode.i_mode = statbuf.st_mode;
1101 inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL);
1102 inode.i_links_count = 1;
1103 inode.i_size = statbuf.st_size;
1104 ext2fs_write_inode(fs, newfile, &inode);
1105 retval = ext2fs_write_inode(fs, newfile, &inode);
1106 if (retval) {
1107 com_err(argv[0], retval, "while trying to write inode %d", inode);
1108 close(fd);
1109 return;
1110 }
1111 if (LINUX_S_ISREG(inode.i_mode)) {
1112 retval = copy_file(fd, newfile);
1113 if (retval)
1114 com_err("copy_file", retval, "");
1115 }
1116 close(fd);
1117}
1118
1119void do_mknod(int argc, char *argv[])
1120{
1121 unsigned long mode, major, minor, nr;
1122 ino_t newfile;
1123 errcode_t retval;
1124 struct ext2_inode inode;
1125
1126 if (check_fs_open(argv[0]))
1127 return;
1128 if (argc < 3 || argv[2][1]) {
1129 com_err(argv[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]");
1130 return;
1131 }
1132 mode = minor = major = 0;
1133 switch (argv[2][0]) {
1134 case 'p':
1135 mode = LINUX_S_IFIFO;
1136 nr = 3;
1137 break;
1138 case 'c':
1139 mode = LINUX_S_IFCHR;
1140 nr = 5;
1141 break;
1142 case 'b':
1143 mode = LINUX_S_IFBLK;
1144 nr = 5;
1145 break;
1146 default:
1147 nr = 0;
1148 }
1149 if (nr == 5) {
1150 major = strtoul(argv[3], argv+3, 0);
1151 minor = strtoul(argv[4], argv+4, 0);
1152 if (major > 255 || minor > 255 || argv[3][0] || argv[4][0])
1153 nr = 0;
1154 }
1155 if (argc != nr) {
1156 com_err(argv[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]");
1157 return;
1158 }
1159 if (!(fs->flags & EXT2_FLAG_RW)) {
1160 com_err(argv[0], 0, "read-only filesystem");
1161 return;
1162 }
1163 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
1164 if (retval) {
1165 com_err(argv[0], retval, "");
1166 return;
1167 }
1168 printf("Allocated inode: %ld\n", newfile);
1169 retval = ext2fs_link(fs, cwd, argv[1], newfile, 0);
1170 if (retval) {
1171 if (retval == EXT2_ET_DIR_NO_SPACE) {
1172 retval = ext2fs_expand_dir(fs, cwd);
1173 if (!retval)
1174 retval = ext2fs_link(fs, cwd, argv[1], newfile, 0);
1175 }
1176 if (retval) {
1177 com_err(argv[1], retval, "");
1178 return;
1179 }
1180 }
1181 if (ext2fs_test_inode_bitmap(fs->inode_map,newfile))
1182 com_err(argv[0], 0, "Warning: inode already set");
1183 ext2fs_mark_inode_bitmap(fs->inode_map,newfile);
1184 ext2fs_mark_ib_dirty(fs);
1185 memset(&inode, 0, sizeof(inode));
1186 inode.i_mode = mode;
1187 inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL);
1188 inode.i_block[0] = major*256+minor;
1189 inode.i_links_count = 1;
1190 ext2fs_write_inode(fs, newfile, &inode);
1191 retval = ext2fs_write_inode(fs, newfile, &inode);
1192 if (retval) {
1193 com_err(argv[0], retval, "while trying to write inode %d", inode);
1194 return;
1195 }
1196}
1197
Theodore Ts'o3839e651997-04-26 13:21:57 +00001198void do_mkdir(int argc, char *argv[])
1199{
1200 char *cp;
1201 ino_t parent;
1202 char *name;
1203 errcode_t retval;
1204
1205 if (check_fs_open(argv[0]))
1206 return;
1207
1208 if (argc != 2) {
1209 com_err(argv[0], 0, "Usage: mkdir <file>");
1210 return;
1211 }
1212
1213 cp = strrchr(argv[1], '/');
1214 if (cp) {
1215 *cp = 0;
1216 parent = string_to_inode(argv[1]);
1217 if (!parent) {
1218 com_err(argv[1], ENOENT, "");
1219 return;
1220 }
1221 name = cp+1;
1222 } else {
1223 parent = cwd;
1224 name = argv[1];
1225 }
1226
1227
1228 retval = ext2fs_mkdir(fs, parent, 0, name);
1229 if (retval) {
1230 com_err("ext2fs_mkdir", retval, "");
1231 return;
1232 }
1233
1234}
1235
1236void do_rmdir(int argc, char *argv[])
1237{
1238 printf("Unimplemented\n");
1239}
1240
1241
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001242static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
1243 int blockcnt, void *private)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001244{
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001245 printf("%d ", *blocknr);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001246 ext2fs_unmark_block_bitmap(fs->block_map,*blocknr);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001247 return 0;
1248}
1249
1250void kill_file_by_inode(ino_t inode)
1251{
1252 struct ext2_inode inode_buf;
1253
1254 ext2fs_read_inode(fs, inode, &inode_buf);
1255 inode_buf.i_dtime = time(NULL);
1256 ext2fs_write_inode(fs, inode, &inode_buf);
1257
1258 printf("Kill file by inode %ld\n", inode);
1259 ext2fs_block_iterate(fs,inode,0,NULL,release_blocks_proc,NULL);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001260 ext2fs_unmark_inode_bitmap(fs->inode_map,inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001261
1262 ext2fs_mark_bb_dirty(fs);
1263 ext2fs_mark_ib_dirty(fs);
1264}
1265
1266
1267void do_kill_file(int argc, char *argv[])
1268{
1269 ino_t inode_num;
1270
1271 if (argc != 2) {
1272 com_err(argv[0], 0, "Usage: kill_file <file>");
1273 return;
1274 }
1275 if (check_fs_open(argv[0]))
1276 return;
1277
1278 inode_num = string_to_inode(argv[1]);
1279 if (!inode_num) {
1280 com_err(argv[0], 0, "Cannot find file");
1281 return;
1282 }
1283 kill_file_by_inode(inode_num);
1284}
1285
1286void do_rm(int argc, char *argv[])
1287{
1288 int retval;
1289 ino_t inode_num;
1290 struct ext2_inode inode;
1291
1292 if (argc != 2) {
1293 com_err(argv[0], 0, "Usage: rm <filename>");
1294 return;
1295 }
1296 if (check_fs_open(argv[0]))
1297 return;
1298
1299 retval = ext2fs_namei(fs, root, cwd, argv[1], &inode_num);
1300 if (retval) {
1301 com_err(argv[0], 0, "Cannot find file");
1302 return;
1303 }
1304
1305 retval = ext2fs_read_inode(fs,inode_num,&inode);
1306 if (retval) {
1307 com_err(argv[0], retval, "while reading file's inode");
1308 return;
1309 }
1310
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001311 if (LINUX_S_ISDIR(inode.i_mode)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +00001312 com_err(argv[0], 0, "file is a directory");
1313 return;
1314 }
1315
1316 --inode.i_links_count;
1317 retval = ext2fs_write_inode(fs,inode_num,&inode);
1318 if (retval) {
1319 com_err(argv[0], retval, "while writing inode");
1320 return;
1321 }
1322
1323 unlink_file_by_name(argv[1]);
1324 if (inode.i_links_count == 0)
1325 kill_file_by_inode(inode_num);
1326}
1327
1328void do_show_debugfs_params(int argc, char *argv[])
1329{
1330 FILE *out = stdout;
1331
1332 fprintf(out, "Open mode: read-%s\n",
1333 fs->flags & EXT2_FLAG_RW ? "write" : "only");
1334 fprintf(out, "Filesystem in use: %s\n",
1335 fs ? fs->device_name : "--none--");
1336}
1337
1338void do_expand_dir(int argc, char *argv[])
1339{
1340 ino_t inode;
1341 int retval;
1342
1343 if (argc != 2) {
1344 com_err(argv[0], 0, "Usage: expand_dir <file>");
1345 return;
1346 }
1347 if (check_fs_open(argv[0]))
1348 return;
1349 inode = string_to_inode(argv[1]);
1350 if (!inode)
1351 return;
1352
1353 retval = ext2fs_expand_dir(fs, inode);
1354 if (retval)
1355 com_err("ext2fs_expand_dir", retval, "");
1356 return;
1357}
1358
1359void main(int argc, char **argv)
1360{
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001361 int retval;
1362 int sci_idx;
1363 const char *usage = "Usage: debugfs [[-w] device]";
1364 char c;
1365 int open_flags = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001366
1367 initialize_ext2_error_table();
1368
1369 while ((c = getopt (argc, argv, "w")) != EOF) {
1370 switch (c) {
1371 case 'w':
1372 open_flags = EXT2_FLAG_RW;
1373 break;
1374 default:
1375 com_err(argv[0], 0, usage);
1376 return;
1377 }
1378 }
1379 if (optind < argc)
1380 open_filesystem(argv[optind], open_flags);
1381
1382 sci_idx = ss_create_invocation("debugfs", "0.0", (char *) NULL,
1383 &debug_cmds, &retval);
1384 if (retval) {
1385 ss_perror(sci_idx, retval, "creating invocation");
1386 exit(1);
1387 }
1388
1389 (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval);
1390 if (retval) {
1391 ss_perror(sci_idx, retval, "adding standard requests");
1392 exit (1);
1393 }
1394
1395 ss_listen(sci_idx);
1396
1397 if (fs)
1398 close_filesystem();
1399
1400 exit(0);
1401}
1402