]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blob - debugfs/debugfs.c
Many files:
[thirdparty/e2fsprogs.git] / debugfs / debugfs.c
1 /*
2 * debugfs.c --- a program which allows you to attach an ext2fs
3 * filesystem and play with it.
4 *
5 * Copyright (C) 1993 Theodore Ts'o. This file may be redistributed
6 * under the terms of the GNU Public License.
7 *
8 * Modifications by Robert Sanders <gt8134b@prism.gatech.edu>
9 */
10
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15 #include <string.h>
16 #include <time.h>
17 #ifdef HAVE_GETOPT_H
18 #include <getopt.h>
19 #else
20 extern int optind;
21 extern char *optarg;
22 #endif
23 #ifdef HAVE_OPTRESET
24 extern int optreset; /* defined by BSD, but not others */
25 #endif
26 #ifdef HAVE_ERRNO_H
27 #include <errno.h>
28 #endif
29 #include <fcntl.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32
33 #include "et/com_err.h"
34 #include "ss/ss.h"
35 #include "debugfs.h"
36
37 extern ss_request_table debug_cmds;
38
39 ext2_filsys fs = NULL;
40 ino_t root, cwd;
41
42 static void open_filesystem(char *device, int open_flags)
43 {
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
65 errout:
66 retval = ext2fs_close(fs);
67 if (retval)
68 com_err(device, retval, "while trying to close filesystem");
69 fs = NULL;
70 }
71
72 void do_open_filesys(int argc, char **argv)
73 {
74 const char *usage = "Usage: open [-w] <device>";
75 char c;
76 int open_flags = 0;
77
78 optind = 1;
79 #ifdef HAVE_OPTRESET
80 optreset = 1; /* Makes BSD getopt happy */
81 #endif
82 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
101 static void close_filesystem(NOARGS)
102 {
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
122 void 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
133 void do_init_filesys(int argc, char **argv)
134 {
135 const char *usage = "Usage: initialize <device> <blocksize>";
136 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
163 void 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));
184 fprintf(out, "Inode size = %d\n", EXT2_INODE_SIZE(fs->super));
185 fprintf(out, "%d inodes, %d free\n", fs->super->s_inodes_count,
186 fs->super->s_free_inodes_count);
187 fprintf(out, "%d blocks, %d free, %d reserved, first block = %d\n",
188 fs->super->s_blocks_count, fs->super->s_free_blocks_count,
189 fs->super->s_r_blocks_count, fs->super->s_first_data_block);
190 fprintf(out, "%d blocks per group\n", fs->super->s_blocks_per_group);
191 fprintf(out, "%d fragments per group\n", fs->super->s_frags_per_group);
192 fprintf(out, "%d inodes per group\n", EXT2_INODES_PER_GROUP(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++)
197 fprintf(out, " Group %2d: block bitmap at %d, "
198 "inode bitmap at %d, "
199 "inode table at %d\n"
200 " %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
215 struct list_blocks_struct {
216 FILE *f;
217 int total;
218 };
219
220 static int list_blocks_proc(ext2_filsys fs, blk_t *blocknr, int blockcnt,
221 void *private)
222 {
223 struct list_blocks_struct *lb = (struct list_blocks_struct *) private;
224
225 fprintf(lb->f, "%d ", *blocknr);
226 lb->total++;
227 return 0;
228 }
229
230
231 static void dump_blocks(FILE *f, ino_t inode)
232 {
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
245 static void dump_inode(ino_t inode_num, struct ext2_inode inode)
246 {
247 const char *i_type;
248 FILE *out;
249
250 out = open_pager();
251 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";
258 else i_type = "bad type";
259 fprintf(out, "Inode: %ld Type: %s ", inode_num, i_type);
260 fprintf(out, "Mode: %04o Flags: 0x%x Version: %d\n",
261 inode.i_mode & 0777, inode.i_flags, inode.i_version);
262 fprintf(out, "User: %5d Group: %5d Size: %d\n",
263 inode.i_uid, inode.i_gid, inode.i_size);
264 if (fs->super->s_creator_os == EXT2_OS_HURD)
265 fprintf(out,
266 "File ACL: %d Directory ACL: %d Translator: %d\n",
267 inode.i_file_acl, inode.i_dir_acl,
268 inode.osd1.hurd1.h_i_translator);
269 else
270 fprintf(out, "File ACL: %d Directory ACL: %d\n",
271 inode.i_file_acl, inode.i_dir_acl);
272 fprintf(out, "Links: %d Blockcount: %d\n", inode.i_links_count,
273 inode.i_blocks);
274 #if HAVE_EXT2_FRAGS
275 fprintf(out, "Fragment: Address: %d Number: %d Size: %d\n",
276 inode.i_faddr, inode.i_frag, inode.i_fsize);
277 #endif
278 fprintf(out, "ctime: 0x%08x -- %s", inode.i_ctime,
279 ctime(&inode.i_ctime));
280 fprintf(out, "atime: 0x%08x -- %s", inode.i_atime,
281 ctime(&inode.i_atime));
282 fprintf(out, "mtime: 0x%08x -- %s", inode.i_mtime,
283 ctime(&inode.i_mtime));
284 if (inode.i_dtime)
285 fprintf(out, "dtime: 0x%08x -- %s", inode.i_dtime,
286 ctime(&inode.i_dtime));
287 if (LINUX_S_ISLNK(inode.i_mode) && inode.i_blocks == 0)
288 fprintf(out, "Fast_link_dest: %s\n", (char *)inode.i_block);
289 else
290 dump_blocks(out, inode_num);
291 close_pager(out);
292 }
293
294
295 void do_stat(int argc, char *argv[])
296 {
297 ino_t inode;
298 struct ext2_inode inode_buf;
299 int retval;
300
301 if (argc != 2) {
302 com_err(argv[0], 0, "Usage: stat <file>");
303 return;
304 }
305 if (check_fs_open(argv[0]))
306 return;
307 inode = string_to_inode(argv[1]);
308 if (!inode)
309 return;
310
311 retval = ext2fs_read_inode(fs,inode,&inode_buf);
312 if (retval)
313 {
314 com_err(argv[0], 0, "Reading inode");
315 return;
316 }
317
318 dump_inode(inode,inode_buf);
319 return;
320 }
321
322 void do_chroot(int argc, char *argv[])
323 {
324 ino_t inode;
325 int retval;
326
327 if (argc != 2) {
328 com_err(argv[0], 0, "Usage: chroot <file>");
329 return;
330 }
331 if (check_fs_open(argv[0]))
332 return;
333 inode = string_to_inode(argv[1]);
334 if (!inode)
335 return;
336
337 retval = ext2fs_check_directory(fs, inode);
338 if (retval) {
339 com_err(argv[1], retval, "");
340 return;
341 }
342 root = inode;
343 }
344
345 void do_clri(int argc, char *argv[])
346 {
347 ino_t inode;
348 int retval;
349 struct ext2_inode inode_buf;
350
351 if (argc != 2) {
352 com_err(argv[0], 0, "Usage: clri <file>");
353 return;
354 }
355 if (check_fs_open(argv[0]))
356 return;
357 if (!(fs->flags & EXT2_FLAG_RW)) {
358 com_err(argv[0], 0, "Filesystem opened read/only");
359 return;
360 }
361 inode = string_to_inode(argv[1]);
362 if (!inode)
363 return;
364
365 retval = ext2fs_read_inode(fs, inode, &inode_buf);
366 if (retval) {
367 com_err(argv[0], 0, "while trying to read inode %d", inode);
368 return;
369 }
370 memset(&inode_buf, 0, sizeof(inode_buf));
371 retval = ext2fs_write_inode(fs, inode, &inode_buf);
372 if (retval) {
373 com_err(argv[0], retval, "while trying to write inode %d",
374 inode);
375 return;
376 }
377 }
378
379 void do_freei(int argc, char *argv[])
380 {
381 ino_t inode;
382
383 if (argc != 2) {
384 com_err(argv[0], 0, "Usage: freei <file>");
385 return;
386 }
387 if (check_fs_open(argv[0]))
388 return;
389 if (!(fs->flags & EXT2_FLAG_RW)) {
390 com_err(argv[0], 0, "Filesystem opened read/only");
391 return;
392 }
393 inode = string_to_inode(argv[1]);
394 if (!inode)
395 return;
396
397 if (!ext2fs_test_inode_bitmap(fs->inode_map,inode))
398 com_err(argv[0], 0, "Warning: inode already clear");
399 ext2fs_unmark_inode_bitmap(fs->inode_map,inode);
400 ext2fs_mark_ib_dirty(fs);
401 }
402
403 void do_seti(int argc, char *argv[])
404 {
405 ino_t inode;
406
407 if (argc != 2) {
408 com_err(argv[0], 0, "Usage: seti <file>");
409 return;
410 }
411 if (check_fs_open(argv[0]))
412 return;
413 if (!(fs->flags & EXT2_FLAG_RW)) {
414 com_err(argv[0], 0, "Filesystem opened read/only");
415 return;
416 }
417 inode = string_to_inode(argv[1]);
418 if (!inode)
419 return;
420
421 if (ext2fs_test_inode_bitmap(fs->inode_map,inode))
422 com_err(argv[0], 0, "Warning: inode already set");
423 ext2fs_mark_inode_bitmap(fs->inode_map,inode);
424 ext2fs_mark_ib_dirty(fs);
425 }
426
427 void do_testi(int argc, char *argv[])
428 {
429 ino_t inode;
430
431 if (argc != 2) {
432 com_err(argv[0], 0, "Usage: testi <file>");
433 return;
434 }
435 if (check_fs_open(argv[0]))
436 return;
437 inode = string_to_inode(argv[1]);
438 if (!inode)
439 return;
440
441 if (ext2fs_test_inode_bitmap(fs->inode_map,inode))
442 printf("Inode %ld is marked in use\n", inode);
443 else
444 printf("Inode %ld is not in use\n", inode);
445 }
446
447
448 void do_freeb(int argc, char *argv[])
449 {
450 blk_t block;
451 char *tmp;
452
453 if (argc != 2) {
454 com_err(argv[0], 0, "Usage: freeb <block>");
455 return;
456 }
457 if (check_fs_open(argv[0]))
458 return;
459 if (!(fs->flags & EXT2_FLAG_RW)) {
460 com_err(argv[0], 0, "Filesystem opened read/only");
461 return;
462 }
463 block = strtoul(argv[1], &tmp, 0);
464 if (!block || *tmp) {
465 com_err(argv[0], 0, "No block 0");
466 return;
467 }
468 if (!ext2fs_test_block_bitmap(fs->block_map,block))
469 com_err(argv[0], 0, "Warning: block already clear");
470 ext2fs_unmark_block_bitmap(fs->block_map,block);
471 ext2fs_mark_bb_dirty(fs);
472 }
473
474 void do_setb(int argc, char *argv[])
475 {
476 blk_t block;
477 char *tmp;
478
479 if (argc != 2) {
480 com_err(argv[0], 0, "Usage: setb <block>");
481 return;
482 }
483 if (check_fs_open(argv[0]))
484 return;
485 if (!(fs->flags & EXT2_FLAG_RW)) {
486 com_err(argv[0], 0, "Filesystem opened read/only");
487 return;
488 }
489 block = strtoul(argv[1], &tmp, 0);
490 if (!block || *tmp) {
491 com_err(argv[0], 0, "No block 0");
492 return;
493 }
494 if (ext2fs_test_block_bitmap(fs->block_map,block))
495 com_err(argv[0], 0, "Warning: block already set");
496 ext2fs_mark_block_bitmap(fs->block_map,block);
497 ext2fs_mark_bb_dirty(fs);
498 }
499
500 void do_testb(int argc, char *argv[])
501 {
502 blk_t block;
503 char *tmp;
504
505 if (argc != 2) {
506 com_err(argv[0], 0, "Usage: testb <block>");
507 return;
508 }
509 if (check_fs_open(argv[0]))
510 return;
511 block = strtoul(argv[1], &tmp, 0);
512 if (!block || *tmp) {
513 com_err(argv[0], 0, "No block 0");
514 return;
515 }
516 if (ext2fs_test_block_bitmap(fs->block_map,block))
517 printf("Block %d marked in use\n", block);
518 else printf("Block %d not in use\n", block);
519 }
520
521 static void modify_u8(char *com, const char *prompt,
522 const char *format, __u8 *val)
523 {
524 char buf[200];
525 u_char v;
526 char *tmp;
527
528 sprintf(buf, format, *val);
529 printf("%30s [%s] ", prompt, buf);
530 fgets(buf, sizeof(buf), stdin);
531 if (buf[strlen (buf) - 1] == '\n')
532 buf[strlen (buf) - 1] = '\0';
533 if (!buf[0])
534 return;
535 v = strtol(buf, &tmp, 0);
536 if (*tmp)
537 com_err(com, 0, "Bad value - %s", buf);
538 else
539 *val = v;
540 }
541
542 static void modify_u16(char *com, const char *prompt,
543 const char *format, __u16 *val)
544 {
545 char buf[200];
546 u_short v;
547 char *tmp;
548
549 sprintf(buf, format, *val);
550 printf("%30s [%s] ", prompt, buf);
551 fgets(buf, sizeof(buf), stdin);
552 if (buf[strlen (buf) - 1] == '\n')
553 buf[strlen (buf) - 1] = '\0';
554 if (!buf[0])
555 return;
556 v = strtol(buf, &tmp, 0);
557 if (*tmp)
558 com_err(com, 0, "Bad value - %s", buf);
559 else
560 *val = v;
561 }
562
563 static void modify_u32(char *com, const char *prompt,
564 const char *format, __u32 *val)
565 {
566 char buf[200];
567 u_long v;
568 char *tmp;
569
570 sprintf(buf, format, *val);
571 printf("%30s [%s] ", prompt, buf);
572 fgets(buf, sizeof(buf), stdin);
573 if (buf[strlen (buf) - 1] == '\n')
574 buf[strlen (buf) - 1] = '\0';
575 if (!buf[0])
576 return;
577 v = strtol(buf, &tmp, 0);
578 if (*tmp)
579 com_err(com, 0, "Bad value - %s", buf);
580 else
581 *val = v;
582 }
583
584
585 void do_modify_inode(int argc, char *argv[])
586 {
587 struct ext2_inode inode;
588 ino_t inode_num;
589 int i;
590 errcode_t retval;
591 char buf[80];
592 const char *hex_format = "0x%x";
593 const char *octal_format = "0%o";
594 const char *decimal_format = "%d";
595
596 if (argc != 2) {
597 com_err(argv[0], 0, "Usage: modify_inode <file>");
598 return;
599 }
600 if (check_fs_open(argv[0]))
601 return;
602 if (!(fs->flags & EXT2_FLAG_RW)) {
603 com_err(argv[0], 0, "Filesystem opened read/only");
604 return;
605 }
606
607 inode_num = string_to_inode(argv[1]);
608 if (!inode_num)
609 return;
610
611 retval = ext2fs_read_inode(fs, inode_num, &inode);
612 if (retval) {
613 com_err(argv[1], retval, "while trying to read inode %d",
614 inode_num);
615 return;
616 }
617
618 modify_u16(argv[0], "Mode", octal_format, &inode.i_mode);
619 modify_u16(argv[0], "User ID", decimal_format, &inode.i_uid);
620 modify_u16(argv[0], "Group ID", decimal_format, &inode.i_gid);
621 modify_u32(argv[0], "Size", decimal_format, &inode.i_size);
622 modify_u32(argv[0], "Creation time", decimal_format, &inode.i_ctime);
623 modify_u32(argv[0], "Modification time", decimal_format, &inode.i_mtime);
624 modify_u32(argv[0], "Access time", decimal_format, &inode.i_atime);
625 modify_u32(argv[0], "Deletion time", decimal_format, &inode.i_dtime);
626 modify_u16(argv[0], "Link count", decimal_format, &inode.i_links_count);
627 modify_u32(argv[0], "Block count", decimal_format, &inode.i_blocks);
628 modify_u32(argv[0], "File flags", hex_format, &inode.i_flags);
629 #if 0
630 modify_u32(argv[0], "Reserved1", decimal_format, &inode.i_reserved1);
631 #endif
632 modify_u32(argv[0], "File acl", decimal_format, &inode.i_file_acl);
633 modify_u32(argv[0], "Directory acl", decimal_format, &inode.i_dir_acl);
634
635 if (fs->super->s_creator_os == EXT2_OS_HURD)
636 modify_u32(argv[0], "Translator Block",
637 decimal_format, &inode.osd1.hurd1.h_i_translator);
638
639 modify_u32(argv[0], "Fragment address", decimal_format, &inode.i_faddr);
640 #if HAVE_EXT2_FRAGS
641 modify_u8(argv[0], "Fragment number", decimal_format, &inode.i_frag);
642 modify_u8(argv[0], "Fragment size", decimal_format, &inode.i_fsize);
643 #endif
644 for (i=0; i < EXT2_NDIR_BLOCKS; i++) {
645 sprintf(buf, "Direct Block #%d", i);
646 modify_u32(argv[0], buf, decimal_format, &inode.i_block[i]);
647 }
648 modify_u32(argv[0], "Indirect Block", decimal_format,
649 &inode.i_block[EXT2_IND_BLOCK]);
650 modify_u32(argv[0], "Double Indirect Block", decimal_format,
651 &inode.i_block[EXT2_DIND_BLOCK]);
652 modify_u32(argv[0], "Triple Indirect Block", decimal_format,
653 &inode.i_block[EXT2_TIND_BLOCK]);
654 retval = ext2fs_write_inode(fs, inode_num, &inode);
655 if (retval) {
656 com_err(argv[1], retval, "while trying to write inode %d",
657 inode_num);
658 return;
659 }
660 }
661
662 /*
663 * list directory
664 */
665
666 struct list_dir_struct {
667 FILE *f;
668 int col;
669 };
670
671 static int list_dir_proc(struct ext2_dir_entry *dirent,
672 int offset,
673 int blocksize,
674 char *buf,
675 void *private)
676 {
677 char name[EXT2_NAME_LEN];
678 char tmp[EXT2_NAME_LEN + 16];
679
680 struct list_dir_struct *ls = (struct list_dir_struct *) private;
681 int thislen;
682
683 thislen = (dirent->name_len < EXT2_NAME_LEN) ? dirent->name_len :
684 EXT2_NAME_LEN;
685 strncpy(name, dirent->name, thislen);
686 name[thislen] = '\0';
687
688 sprintf(tmp, "%d (%d) %s ", dirent->inode, dirent->rec_len, name);
689 thislen = strlen(tmp);
690
691 if (ls->col + thislen > 80) {
692 fprintf(ls->f, "\n");
693 ls->col = 0;
694 }
695 fprintf(ls->f, "%s", tmp);
696 ls->col += thislen;
697
698 return 0;
699 }
700
701 void do_list_dir(int argc, char *argv[])
702 {
703 ino_t inode;
704 int retval;
705 struct list_dir_struct ls;
706
707 if (argc > 2) {
708 com_err(argv[0], 0, "Usage: list_dir [pathname]");
709 return;
710 }
711 if (check_fs_open(argv[0]))
712 return;
713
714 if (argc == 2)
715 inode = string_to_inode(argv[1]);
716 else
717 inode = cwd;
718 if (!inode)
719 return;
720
721 ls.f = open_pager();
722 ls.col = 0;
723 retval = ext2fs_dir_iterate(fs, inode, DIRENT_FLAG_INCLUDE_EMPTY,
724 0, list_dir_proc, &ls);
725 fprintf(ls.f, "\n");
726 close_pager(ls.f);
727 if (retval)
728 com_err(argv[1], retval, "");
729
730 return;
731 }
732
733 void do_change_working_dir(int argc, char *argv[])
734 {
735 ino_t inode;
736 int retval;
737
738 if (argc != 2) {
739 com_err(argv[0], 0, "Usage: cd <file>");
740 return;
741 }
742 if (check_fs_open(argv[0]))
743 return;
744
745 inode = string_to_inode(argv[1]);
746 if (!inode)
747 return;
748
749 retval = ext2fs_check_directory(fs, inode);
750 if (retval) {
751 com_err(argv[1], retval, "");
752 return;
753 }
754 cwd = inode;
755 return;
756 }
757
758 void do_print_working_directory(int argc, char *argv[])
759 {
760 int retval;
761 char *pathname = NULL;
762
763 if (argc > 1) {
764 com_err(argv[0], 0, "Usage: print_working_directory");
765 return;
766 }
767 if (check_fs_open(argv[0]))
768 return;
769
770 retval = ext2fs_get_pathname(fs, cwd, 0, &pathname);
771 if (retval) {
772 com_err(argv[0], retval,
773 "while trying to get pathname of cwd");
774 }
775 printf("[pwd] INODE: %6ld PATH: %s\n", cwd, pathname);
776 free(pathname);
777 retval = ext2fs_get_pathname(fs, root, 0, &pathname);
778 if (retval) {
779 com_err(argv[0], retval,
780 "while trying to get pathname of root");
781 }
782 printf("[root] INODE: %6ld PATH: %s\n", root, pathname);
783 free(pathname);
784 return;
785 }
786
787 static void make_link(char *sourcename, char *destname)
788 {
789 ino_t inode;
790 int retval;
791 ino_t dir;
792 char *dest, *cp, *basename;
793
794 /*
795 * Get the source inode
796 */
797 inode = string_to_inode(sourcename);
798 if (!inode)
799 return;
800 basename = strrchr(sourcename, '/');
801 if (basename)
802 basename++;
803 else
804 basename = sourcename;
805 /*
806 * Figure out the destination. First see if it exists and is
807 * a directory.
808 */
809 if (! (retval=ext2fs_namei(fs, root, cwd, destname, &dir)))
810 dest = basename;
811 else {
812 /*
813 * OK, it doesn't exist. See if it is
814 * '<dir>/basename' or 'basename'
815 */
816 cp = strrchr(destname, '/');
817 if (cp) {
818 *cp = 0;
819 dir = string_to_inode(destname);
820 if (!dir)
821 return;
822 dest = cp+1;
823 } else {
824 dir = cwd;
825 dest = destname;
826 }
827 }
828
829 retval = ext2fs_link(fs, dir, dest, inode, 0);
830 if (retval)
831 com_err("make_link", retval, "");
832 return;
833 }
834
835
836 void do_link(int argc, char *argv[])
837 {
838 if (argc != 3) {
839 com_err(argv[0], 0, "Usage: link <source_file> <dest_name>");
840 return;
841 }
842 if (check_fs_open(argv[0]))
843 return;
844
845 make_link(argv[1], argv[2]);
846 }
847
848 static void unlink_file_by_name(char *filename)
849 {
850 int retval;
851 ino_t dir;
852 char *basename;
853
854 basename = strrchr(filename, '/');
855 if (basename) {
856 *basename++ = '0';
857 dir = string_to_inode(filename);
858 if (!dir)
859 return;
860 } else {
861 dir = cwd;
862 basename = filename;
863 }
864 retval = ext2fs_unlink(fs, dir, basename, 0, 0);
865 if (retval)
866 com_err("unlink_file_by_name", retval, "");
867 return;
868 }
869
870 void do_unlink(int argc, char *argv[])
871 {
872 if (argc != 2) {
873 com_err(argv[0], 0, "Usage: unlink <pathname>");
874 return;
875 }
876 if (check_fs_open(argv[0]))
877 return;
878
879 unlink_file_by_name(argv[1]);
880 }
881
882 void do_find_free_block(int argc, char *argv[])
883 {
884 blk_t free_blk, goal;
885 errcode_t retval;
886 char *tmp;
887
888 if ((argc > 2) || (argc==2 && *argv[1] == '?')) {
889 com_err(argv[0], 0, "Usage: find_free_block [goal]");
890 return;
891 }
892 if (check_fs_open(argv[0]))
893 return;
894
895 if (argc > 1) {
896 goal = strtol(argv[1], &tmp, 0);
897 if (*tmp) {
898 com_err(argv[0], 0, "Bad goal - %s", argv[1]);
899 return;
900 }
901 }
902 else
903 goal = fs->super->s_first_data_block;
904
905 retval = ext2fs_new_block(fs, goal, 0, &free_blk);
906 if (retval)
907 com_err("ext2fs_new_block", retval, "");
908 else
909 printf("Free block found: %d\n", free_blk);
910
911 }
912
913 void do_find_free_inode(int argc, char *argv[])
914 {
915 ino_t free_inode, dir;
916 int mode;
917 int retval;
918 char *tmp;
919
920 if (argc > 3 || (argc>1 && *argv[1] == '?')) {
921 com_err(argv[0], 0, "Usage: find_free_inode [dir] [mode]");
922 return;
923 }
924 if (check_fs_open(argv[0]))
925 return;
926
927 if (argc > 1) {
928 dir = strtol(argv[1], &tmp, 0);
929 if (*tmp) {
930 com_err(argv[0], 0, "Bad dir - %s", argv[1]);
931 return;
932 }
933 }
934 else
935 dir = root;
936 if (argc > 2) {
937 mode = strtol(argv[2], &tmp, 0);
938 if (*tmp) {
939 com_err(argv[0], 0, "Bad mode - %s", argv[2]);
940 return;
941 }
942 } else
943 mode = 010755;
944
945 retval = ext2fs_new_inode(fs, dir, mode, 0, &free_inode);
946 if (retval)
947 com_err("ext2fs_new_inode", retval, "");
948 else
949 printf("Free inode found: %ld\n", free_inode);
950 }
951
952 struct copy_file_struct {
953 unsigned long size;
954 int done, fd, blocks;
955 errcode_t err;
956 };
957
958 static int copy_file_proc(ext2_filsys fs,
959 blk_t *blocknr,
960 int blockcnt,
961 void *private)
962 {
963 struct copy_file_struct *cs = (struct copy_file_struct *) private;
964 blk_t new_blk;
965 static blk_t last_blk = 0;
966 char *block;
967 errcode_t retval;
968 int group;
969 int nr;
970
971 if (*blocknr) {
972 new_blk = *blocknr;
973 } else {
974 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
975 if (retval) {
976 cs->err = retval;
977 return BLOCK_ABORT;
978 }
979 }
980 last_blk = new_blk;
981 block = malloc(fs->blocksize);
982 if (!block) {
983 cs->err = ENOMEM;
984 return BLOCK_ABORT;
985 }
986 if (blockcnt >= 0) {
987 nr = read(cs->fd, block, fs->blocksize);
988 } else {
989 nr = fs->blocksize;
990 memset(block, 0, nr);
991 }
992 if (nr == 0) {
993 cs->done = 1;
994 return BLOCK_ABORT;
995 }
996 if (nr < 0) {
997 cs->err = nr;
998 return BLOCK_ABORT;
999 }
1000 retval = io_channel_write_blk(fs->io, new_blk, 1, block);
1001 if (retval) {
1002 cs->err = retval;
1003 return BLOCK_ABORT;
1004 }
1005 free(block);
1006 if (blockcnt >= 0)
1007 cs->size += nr;
1008 cs->blocks += fs->blocksize / 512;
1009 printf("%ld(%d) ", cs->size, blockcnt);
1010 fflush(stdout);
1011 if (nr < fs->blocksize) {
1012 cs->done = 1;
1013 printf("\n");
1014 }
1015 *blocknr = new_blk;
1016 ext2fs_mark_block_bitmap(fs->block_map, new_blk);
1017 ext2fs_mark_bb_dirty(fs);
1018 group = ext2fs_group_of_blk(fs, new_blk);
1019 fs->group_desc[group].bg_free_blocks_count--;
1020 fs->super->s_free_blocks_count--;
1021 ext2fs_mark_super_dirty(fs);
1022 if (cs->done)
1023 return (BLOCK_CHANGED | BLOCK_ABORT);
1024 else
1025 return BLOCK_CHANGED;
1026 }
1027
1028 static errcode_t copy_file(int fd, ino_t newfile)
1029 {
1030 errcode_t retval;
1031 struct copy_file_struct cs;
1032 struct ext2_inode inode;
1033
1034 cs.fd = fd;
1035 cs.done = 0;
1036 cs.err = 0;
1037 cs.size = 0;
1038 cs.blocks = 0;
1039
1040 retval = ext2fs_block_iterate(fs, newfile, BLOCK_FLAG_APPEND,
1041 0, copy_file_proc, &cs);
1042
1043 if (cs.err)
1044 return cs.err;
1045 if (!cs.done)
1046 return EXT2_ET_EXPAND_DIR_ERR;
1047
1048 /*
1049 * Update the size and block count fields in the inode.
1050 */
1051 retval = ext2fs_read_inode(fs, newfile, &inode);
1052 if (retval)
1053 return retval;
1054
1055 inode.i_blocks += cs.blocks;
1056
1057 retval = ext2fs_write_inode(fs, newfile, &inode);
1058 if (retval)
1059 return retval;
1060
1061 return 0;
1062 }
1063
1064 void do_write(int argc, char *argv[])
1065 {
1066 int fd;
1067 struct stat statbuf;
1068 ino_t newfile;
1069 errcode_t retval;
1070 struct ext2_inode inode;
1071
1072 if (check_fs_open(argv[0]))
1073 return;
1074 if (argc != 3) {
1075 com_err(argv[0], 0, "Usage: write <nativefile> <newfile>");
1076 return;
1077 }
1078 if (!(fs->flags & EXT2_FLAG_RW)) {
1079 com_err(argv[0], 0, "read-only filesystem");
1080 return;
1081 }
1082 fd = open(argv[1], O_RDONLY);
1083 if (fd < 0) {
1084 com_err(argv[1], fd, "");
1085 return;
1086 }
1087 if (fstat(fd, &statbuf) < 0) {
1088 com_err(argv[1], errno, "");
1089 close(fd);
1090 return;
1091 }
1092
1093 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
1094 if (retval) {
1095 com_err(argv[0], retval, "");
1096 close(fd);
1097 return;
1098 }
1099 printf("Allocated inode: %ld\n", newfile);
1100 retval = ext2fs_link(fs, cwd, argv[2], newfile, 0);
1101 if (retval) {
1102 com_err(argv[2], retval, "");
1103 close(fd);
1104 return;
1105 }
1106 if (ext2fs_test_inode_bitmap(fs->inode_map,newfile))
1107 com_err(argv[0], 0, "Warning: inode already set");
1108 ext2fs_mark_inode_bitmap(fs->inode_map,newfile);
1109 ext2fs_mark_ib_dirty(fs);
1110 memset(&inode, 0, sizeof(inode));
1111 inode.i_mode = statbuf.st_mode;
1112 inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL);
1113 inode.i_links_count = 1;
1114 inode.i_size = statbuf.st_size;
1115 ext2fs_write_inode(fs, newfile, &inode);
1116 retval = ext2fs_write_inode(fs, newfile, &inode);
1117 if (retval) {
1118 com_err(argv[0], retval, "while trying to write inode %d", inode);
1119 close(fd);
1120 return;
1121 }
1122 if (LINUX_S_ISREG(inode.i_mode)) {
1123 retval = copy_file(fd, newfile);
1124 if (retval)
1125 com_err("copy_file", retval, "");
1126 }
1127 close(fd);
1128 }
1129
1130 void do_mknod(int argc, char *argv[])
1131 {
1132 unsigned long mode, major, minor, nr;
1133 ino_t newfile;
1134 errcode_t retval;
1135 struct ext2_inode inode;
1136
1137 if (check_fs_open(argv[0]))
1138 return;
1139 if (argc < 3 || argv[2][1]) {
1140 com_err(argv[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]");
1141 return;
1142 }
1143 mode = minor = major = 0;
1144 switch (argv[2][0]) {
1145 case 'p':
1146 mode = LINUX_S_IFIFO;
1147 nr = 3;
1148 break;
1149 case 'c':
1150 mode = LINUX_S_IFCHR;
1151 nr = 5;
1152 break;
1153 case 'b':
1154 mode = LINUX_S_IFBLK;
1155 nr = 5;
1156 break;
1157 default:
1158 nr = 0;
1159 }
1160 if (nr == 5) {
1161 major = strtoul(argv[3], argv+3, 0);
1162 minor = strtoul(argv[4], argv+4, 0);
1163 if (major > 255 || minor > 255 || argv[3][0] || argv[4][0])
1164 nr = 0;
1165 }
1166 if (argc != nr) {
1167 com_err(argv[0], 0, "Usage: mknod <name> [p| [c|b] <major> <minor>]");
1168 return;
1169 }
1170 if (!(fs->flags & EXT2_FLAG_RW)) {
1171 com_err(argv[0], 0, "read-only filesystem");
1172 return;
1173 }
1174 retval = ext2fs_new_inode(fs, cwd, 010755, 0, &newfile);
1175 if (retval) {
1176 com_err(argv[0], retval, "");
1177 return;
1178 }
1179 printf("Allocated inode: %ld\n", newfile);
1180 retval = ext2fs_link(fs, cwd, argv[1], newfile, 0);
1181 if (retval) {
1182 if (retval == EXT2_ET_DIR_NO_SPACE) {
1183 retval = ext2fs_expand_dir(fs, cwd);
1184 if (!retval)
1185 retval = ext2fs_link(fs, cwd, argv[1], newfile, 0);
1186 }
1187 if (retval) {
1188 com_err(argv[1], retval, "");
1189 return;
1190 }
1191 }
1192 if (ext2fs_test_inode_bitmap(fs->inode_map,newfile))
1193 com_err(argv[0], 0, "Warning: inode already set");
1194 ext2fs_mark_inode_bitmap(fs->inode_map,newfile);
1195 ext2fs_mark_ib_dirty(fs);
1196 memset(&inode, 0, sizeof(inode));
1197 inode.i_mode = mode;
1198 inode.i_atime = inode.i_ctime = inode.i_mtime = time(NULL);
1199 inode.i_block[0] = major*256+minor;
1200 inode.i_links_count = 1;
1201 ext2fs_write_inode(fs, newfile, &inode);
1202 retval = ext2fs_write_inode(fs, newfile, &inode);
1203 if (retval) {
1204 com_err(argv[0], retval, "while trying to write inode %d", inode);
1205 return;
1206 }
1207 }
1208
1209 void do_mkdir(int argc, char *argv[])
1210 {
1211 char *cp;
1212 ino_t parent;
1213 char *name;
1214 errcode_t retval;
1215
1216 if (check_fs_open(argv[0]))
1217 return;
1218
1219 if (argc != 2) {
1220 com_err(argv[0], 0, "Usage: mkdir <file>");
1221 return;
1222 }
1223
1224 cp = strrchr(argv[1], '/');
1225 if (cp) {
1226 *cp = 0;
1227 parent = string_to_inode(argv[1]);
1228 if (!parent) {
1229 com_err(argv[1], ENOENT, "");
1230 return;
1231 }
1232 name = cp+1;
1233 } else {
1234 parent = cwd;
1235 name = argv[1];
1236 }
1237
1238
1239 retval = ext2fs_mkdir(fs, parent, 0, name);
1240 if (retval) {
1241 com_err("ext2fs_mkdir", retval, "");
1242 return;
1243 }
1244
1245 }
1246
1247 void do_rmdir(int argc, char *argv[])
1248 {
1249 printf("Unimplemented\n");
1250 }
1251
1252
1253 static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
1254 int blockcnt, void *private)
1255 {
1256 printf("%d ", *blocknr);
1257 ext2fs_unmark_block_bitmap(fs->block_map,*blocknr);
1258 return 0;
1259 }
1260
1261 void kill_file_by_inode(ino_t inode)
1262 {
1263 struct ext2_inode inode_buf;
1264
1265 ext2fs_read_inode(fs, inode, &inode_buf);
1266 inode_buf.i_dtime = time(NULL);
1267 ext2fs_write_inode(fs, inode, &inode_buf);
1268
1269 printf("Kill file by inode %ld\n", inode);
1270 ext2fs_block_iterate(fs,inode,0,NULL,release_blocks_proc,NULL);
1271 ext2fs_unmark_inode_bitmap(fs->inode_map,inode);
1272
1273 ext2fs_mark_bb_dirty(fs);
1274 ext2fs_mark_ib_dirty(fs);
1275 }
1276
1277
1278 void 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
1289 inode_num = string_to_inode(argv[1]);
1290 if (!inode_num) {
1291 com_err(argv[0], 0, "Cannot find file");
1292 return;
1293 }
1294 kill_file_by_inode(inode_num);
1295 }
1296
1297 void do_rm(int argc, char *argv[])
1298 {
1299 int retval;
1300 ino_t inode_num;
1301 struct ext2_inode inode;
1302
1303 if (argc != 2) {
1304 com_err(argv[0], 0, "Usage: rm <filename>");
1305 return;
1306 }
1307 if (check_fs_open(argv[0]))
1308 return;
1309
1310 retval = ext2fs_namei(fs, root, cwd, argv[1], &inode_num);
1311 if (retval) {
1312 com_err(argv[0], 0, "Cannot find file");
1313 return;
1314 }
1315
1316 retval = ext2fs_read_inode(fs,inode_num,&inode);
1317 if (retval) {
1318 com_err(argv[0], retval, "while reading file's inode");
1319 return;
1320 }
1321
1322 if (LINUX_S_ISDIR(inode.i_mode)) {
1323 com_err(argv[0], 0, "file is a directory");
1324 return;
1325 }
1326
1327 --inode.i_links_count;
1328 retval = ext2fs_write_inode(fs,inode_num,&inode);
1329 if (retval) {
1330 com_err(argv[0], retval, "while writing inode");
1331 return;
1332 }
1333
1334 unlink_file_by_name(argv[1]);
1335 if (inode.i_links_count == 0)
1336 kill_file_by_inode(inode_num);
1337 }
1338
1339 void do_show_debugfs_params(int argc, char *argv[])
1340 {
1341 FILE *out = stdout;
1342
1343 fprintf(out, "Open mode: read-%s\n",
1344 fs->flags & EXT2_FLAG_RW ? "write" : "only");
1345 fprintf(out, "Filesystem in use: %s\n",
1346 fs ? fs->device_name : "--none--");
1347 }
1348
1349 void do_expand_dir(int argc, char *argv[])
1350 {
1351 ino_t inode;
1352 int retval;
1353
1354 if (argc != 2) {
1355 com_err(argv[0], 0, "Usage: expand_dir <file>");
1356 return;
1357 }
1358 if (check_fs_open(argv[0]))
1359 return;
1360 inode = string_to_inode(argv[1]);
1361 if (!inode)
1362 return;
1363
1364 retval = ext2fs_expand_dir(fs, inode);
1365 if (retval)
1366 com_err("ext2fs_expand_dir", retval, "");
1367 return;
1368 }
1369
1370 void main(int argc, char **argv)
1371 {
1372 int retval;
1373 int sci_idx;
1374 const char *usage = "Usage: debugfs [[-w] device]";
1375 char c;
1376 int open_flags = 0;
1377
1378 initialize_ext2_error_table();
1379
1380 while ((c = getopt (argc, argv, "w")) != EOF) {
1381 switch (c) {
1382 case 'w':
1383 open_flags = EXT2_FLAG_RW;
1384 break;
1385 default:
1386 com_err(argv[0], 0, usage);
1387 return;
1388 }
1389 }
1390 if (optind < argc)
1391 open_filesystem(argv[optind], open_flags);
1392
1393 sci_idx = ss_create_invocation("debugfs", "0.0", (char *) NULL,
1394 &debug_cmds, &retval);
1395 if (retval) {
1396 ss_perror(sci_idx, retval, "creating invocation");
1397 exit(1);
1398 }
1399
1400 (void) ss_add_request_table (sci_idx, &ss_std_requests, 1, &retval);
1401 if (retval) {
1402 ss_perror(sci_idx, retval, "adding standard requests");
1403 exit (1);
1404 }
1405
1406 ss_listen(sci_idx);
1407
1408 if (fs)
1409 close_filesystem();
1410
1411 exit(0);
1412 }
1413