blob: d05922ad1a0b4784c22c3555b2635225596d23a6 [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"
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +000036#include "uuid/uuid.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000037
Theodore Ts'o818180c1998-06-27 05:11:14 +000038#include "../version.h"
39
Theodore Ts'o3839e651997-04-26 13:21:57 +000040extern ss_request_table debug_cmds;
41
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +000042ext2_filsys current_fs = NULL;
Theodore Ts'o3839e651997-04-26 13:21:57 +000043ino_t root, cwd;
44
Theodore Ts'o50e1e101997-04-26 13:58:21 +000045static void open_filesystem(char *device, int open_flags)
Theodore Ts'o3839e651997-04-26 13:21:57 +000046{
47 int retval;
48
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +000049 retval = ext2fs_open(device, open_flags, 0, 0,
50 unix_io_manager, &current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +000051 if (retval) {
52 com_err(device, retval, "while opening filesystem");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +000053 current_fs = NULL;
Theodore Ts'o3839e651997-04-26 13:21:57 +000054 return;
55 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +000056 retval = ext2fs_read_inode_bitmap(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +000057 if (retval) {
58 com_err(device, retval, "while reading inode bitmap");
59 goto errout;
60 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +000061 retval = ext2fs_read_block_bitmap(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +000062 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:
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +000070 retval = ext2fs_close(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +000071 if (retval)
72 com_err(device, retval, "while trying to close filesystem");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +000073 current_fs = NULL;
Theodore Ts'o3839e651997-04-26 13:21:57 +000074}
75
76void do_open_filesys(int argc, char **argv)
77{
Theodore Ts'o50e1e101997-04-26 13:58:21 +000078 const char *usage = "Usage: open [-w] <device>";
Theodore Ts'of1304811997-10-25 03:51:53 +000079 int c;
Theodore Ts'o3839e651997-04-26 13:21:57 +000080 int open_flags = 0;
81
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +000082 optind = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000083#ifdef HAVE_OPTRESET
84 optreset = 1; /* Makes BSD getopt happy */
85#endif
Theodore Ts'od3aea7d1999-09-14 20:55:37 +000086 while ((c = getopt (argc, argv, "wf")) != EOF) {
Theodore Ts'o3839e651997-04-26 13:21:57 +000087 switch (c) {
88 case 'w':
Theodore Ts'od3aea7d1999-09-14 20:55:37 +000089 open_flags |= EXT2_FLAG_RW;
90 break;
91 case 'f':
92 open_flags |= EXT2_FLAG_FORCE;
Theodore Ts'o3839e651997-04-26 13:21:57 +000093 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
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000108static void close_filesystem(NOARGS)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000109{
110 int retval;
111
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000112 if (current_fs->flags & EXT2_FLAG_IB_DIRTY) {
113 retval = ext2fs_write_inode_bitmap(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000114 if (retval)
115 com_err("ext2fs_write_inode_bitmap", retval, "");
116 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000117 if (current_fs->flags & EXT2_FLAG_BB_DIRTY) {
118 retval = ext2fs_write_block_bitmap(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000119 if (retval)
120 com_err("ext2fs_write_block_bitmap", retval, "");
121 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000122 retval = ext2fs_close(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000123 if (retval)
124 com_err("ext2fs_close", retval, "");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000125 current_fs = NULL;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000126 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{
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000142 const char *usage = "Usage: initialize <device> <blocksize>";
Theodore Ts'o3839e651997-04-26 13:21:57 +0000143 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 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000160 retval = ext2fs_initialize(argv[1], 0, &param,
161 unix_io_manager, &current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000162 if (retval) {
163 com_err(argv[1], retval, "while initializing filesystem");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000164 current_fs = NULL;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000165 return;
166 }
167 root = cwd = EXT2_ROOT_INO;
168 return;
169}
170
Theodore Ts'od3aea7d1999-09-14 20:55:37 +0000171static 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
Theodore Ts'o3839e651997-04-26 13:21:57 +0000192void do_show_super_stats(int argc, char *argv[])
193{
194 int i;
195 FILE *out;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000196 struct ext2fs_sb *sb;
197 struct ext2_group_desc *gdp;
Theodore Ts'od3aea7d1999-09-14 20:55:37 +0000198 int c, header_only = 0;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000199 char buf[80];
200 const char *none = "(none)";
Theodore Ts'od3aea7d1999-09-14 20:55:37 +0000201 const char *usage = "Usage: show_super [-h]";
Theodore Ts'o3839e651997-04-26 13:21:57 +0000202
Theodore Ts'od3aea7d1999-09-14 20:55:37 +0000203 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);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000219 return;
220 }
221 if (check_fs_open(argv[0]))
222 return;
223 out = open_pager();
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000224 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);
Theodore Ts'od3aea7d1999-09-14 20:55:37 +0000244 print_features(sb, out);
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000245 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));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000247 fprintf(out, "Mount counts = %d (maximal = %d)\n",
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000248 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));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000258 fprintf(out, "Block size = %d, fragment size = %d\n",
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000259 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);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000263 fprintf(out, "%d blocks, %d free, %d reserved, first block = %d\n",
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000264 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));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000269 fprintf(out, "%ld group%s (%ld descriptors block%s)\n",
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000270 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" : "");
Theodore Ts'od3aea7d1999-09-14 20:55:37 +0000274
275 if (header_only) {
276 close_pager(out);
277 return;
278 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000279
280 gdp = &current_fs->group_desc[0];
281 for (i = 0; i < current_fs->group_desc_count; i++, gdp++)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000282 fprintf(out, " Group %2d: block bitmap at %d, "
283 "inode bitmap at %d, "
284 "inode table at %d\n"
Theodore Ts'o3839e651997-04-26 13:21:57 +0000285 " %d free block%s, "
286 "%d free inode%s, "
287 "%d used director%s\n",
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000288 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");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000296 close_pager(out);
297}
298
Theodore Ts'o4a31c481998-03-30 01:27:25 +0000299void do_dirty_filesys(int argc, char **argv)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000300{
301 if (check_fs_open(argv[0]))
302 return;
303
304 ext2fs_mark_super_dirty(current_fs);
305}
306
Theodore Ts'o3839e651997-04-26 13:21:57 +0000307struct list_blocks_struct {
308 FILE *f;
309 int total;
310};
311
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000312static int list_blocks_proc(ext2_filsys fs, blk_t *blocknr, int blockcnt,
313 void *private)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000314{
315 struct list_blocks_struct *lb = (struct list_blocks_struct *) private;
316
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000317 fprintf(lb->f, "%d ", *blocknr);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000318 lb->total++;
319 return 0;
320}
321
322
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000323static void dump_blocks(FILE *f, ino_t inode)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000324{
325 struct list_blocks_struct lb;
326
327 fprintf(f, "BLOCKS:\n");
328 lb.total = 0;
329 lb.f = f;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000330 ext2fs_block_iterate(current_fs, inode, 0, NULL,
331 list_blocks_proc, (void *)&lb);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000332 if (lb.total)
333 fprintf(f, "\nTOTAL: %d\n", lb.total);
334 fprintf(f,"\n");
335}
336
337
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000338static void dump_inode(ino_t inode_num, struct ext2_inode inode)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000339{
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000340 const char *i_type;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000341 FILE *out;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000342 char frag, fsize;
343 int os = current_fs->super->s_creator_os;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000344
345 out = open_pager();
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000346 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";
Theodore Ts'o3839e651997-04-26 13:21:57 +0000353 else i_type = "bad type";
354 fprintf(out, "Inode: %ld Type: %s ", inode_num, i_type);
Theodore Ts'ob41d3601999-06-25 15:32:37 +0000355#if defined(HAVE_EXT2_INODE_VERSION)
Theodore Ts'o55376d81999-07-31 00:32:57 +0000356 fprintf(out, "Mode: %04o Flags: 0x%x Version/Generation: %d\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000357 inode.i_mode & 0777, inode.i_flags, inode.i_version);
Theodore Ts'ob41d3601999-06-25 15:32:37 +0000358#else
Theodore Ts'o55376d81999-07-31 00:32:57 +0000359 fprintf(out, "Mode: %04o Flags: 0x%x Version/Generation: %d\n",
Theodore Ts'ob41d3601999-06-25 15:32:37 +0000360 inode.i_mode & 0777, inode.i_flags, inode.i_generation);
361#endif
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000362 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 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000372 if (current_fs->super->s_creator_os == EXT2_OS_HURD)
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000373 fprintf(out,
374 "File ACL: %d Directory ACL: %d Translator: %d\n",
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000375 inode.i_file_acl, LINUX_S_ISDIR(inode.i_mode) ? inode.i_dir_acl : 0,
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000376 inode.osd1.hurd1.h_i_translator);
377 else
378 fprintf(out, "File ACL: %d Directory ACL: %d\n",
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000379 inode.i_file_acl, LINUX_S_ISDIR(inode.i_mode) ? inode.i_dir_acl : 0);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000380 fprintf(out, "Links: %d Blockcount: %d\n", inode.i_links_count,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000381 inode.i_blocks);
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000382 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 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000398 fprintf(out, "Fragment: Address: %d Number: %d Size: %d\n",
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000399 inode.i_faddr, frag, fsize);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000400 fprintf(out, "ctime: 0x%08x -- %s", inode.i_ctime,
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000401 time_to_string(inode.i_ctime));
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000402 fprintf(out, "atime: 0x%08x -- %s", inode.i_atime,
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000403 time_to_string(inode.i_atime));
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000404 fprintf(out, "mtime: 0x%08x -- %s", inode.i_mtime,
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000405 time_to_string(inode.i_mtime));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000406 if (inode.i_dtime)
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000407 fprintf(out, "dtime: 0x%08x -- %s", inode.i_dtime,
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000408 time_to_string(inode.i_dtime));
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000409 if (LINUX_S_ISLNK(inode.i_mode) && inode.i_blocks == 0)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000410 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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000433 retval = ext2fs_read_inode(current_fs, inode, &inode_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000434 if (retval)
435 {
Theodore Ts'o91d6d481998-08-01 01:03:39 +0000436 com_err(argv[0], retval, "while trying to read inode %d", inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000437 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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000459 retval = ext2fs_check_directory(current_fs, inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000460 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;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000479 if (check_fs_read_write(argv[0]))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000480 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000481 inode = string_to_inode(argv[1]);
482 if (!inode)
483 return;
484
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000485 retval = ext2fs_read_inode(current_fs, inode, &inode_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000486 if (retval) {
Theodore Ts'o91d6d481998-08-01 01:03:39 +0000487 com_err(argv[0], retval, "while trying to read inode %d",
488 inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000489 return;
490 }
491 memset(&inode_buf, 0, sizeof(inode_buf));
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000492 retval = ext2fs_write_inode(current_fs, inode, &inode_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000493 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;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000510 if (check_fs_read_write(argv[0]))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000511 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000512 inode = string_to_inode(argv[1]);
513 if (!inode)
514 return;
515
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000516 if (!ext2fs_test_inode_bitmap(current_fs->inode_map,inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000517 com_err(argv[0], 0, "Warning: inode already clear");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000518 ext2fs_unmark_inode_bitmap(current_fs->inode_map,inode);
519 ext2fs_mark_ib_dirty(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000520}
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;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000532 if (check_fs_read_write(argv[0]))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000533 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000534 inode = string_to_inode(argv[1]);
535 if (!inode)
536 return;
537
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000538 if (ext2fs_test_inode_bitmap(current_fs->inode_map,inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000539 com_err(argv[0], 0, "Warning: inode already set");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000540 ext2fs_mark_inode_bitmap(current_fs->inode_map,inode);
541 ext2fs_mark_ib_dirty(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000542}
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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000558 if (ext2fs_test_inode_bitmap(current_fs->inode_map,inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000559 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;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000576 if (check_fs_read_write(argv[0]))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000577 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000578 block = strtoul(argv[1], &tmp, 0);
579 if (!block || *tmp) {
580 com_err(argv[0], 0, "No block 0");
581 return;
582 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000583 if (!ext2fs_test_block_bitmap(current_fs->block_map,block))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000584 com_err(argv[0], 0, "Warning: block already clear");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000585 ext2fs_unmark_block_bitmap(current_fs->block_map,block);
586 ext2fs_mark_bb_dirty(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000587}
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;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000600 if (check_fs_read_write(argv[0]))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000601 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000602 block = strtoul(argv[1], &tmp, 0);
603 if (!block || *tmp) {
604 com_err(argv[0], 0, "No block 0");
605 return;
606 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000607 if (ext2fs_test_block_bitmap(current_fs->block_map,block))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000608 com_err(argv[0], 0, "Warning: block already set");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000609 ext2fs_mark_block_bitmap(current_fs->block_map,block);
610 ext2fs_mark_bb_dirty(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000611}
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 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000629 if (ext2fs_test_block_bitmap(current_fs->block_map,block))
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000630 printf("Block %d marked in use\n", block);
631 else printf("Block %d not in use\n", block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000632}
633
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000634static void modify_u8(char *com, const char *prompt,
635 const char *format, __u8 *val)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000636{
637 char buf[200];
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000638 unsigned long v;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000639 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;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000648 v = strtoul(buf, &tmp, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000649 if (*tmp)
650 com_err(com, 0, "Bad value - %s", buf);
651 else
652 *val = v;
653}
654
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000655static void modify_u16(char *com, const char *prompt,
656 const char *format, __u16 *val)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000657{
658 char buf[200];
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000659 unsigned long v;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000660 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;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000669 v = strtoul(buf, &tmp, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000670 if (*tmp)
671 com_err(com, 0, "Bad value - %s", buf);
672 else
673 *val = v;
674}
675
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000676static void modify_u32(char *com, const char *prompt,
677 const char *format, __u32 *val)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000678{
679 char buf[200];
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000680 unsigned long v;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000681 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;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000690 v = strtoul(buf, &tmp, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000691 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;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000704 unsigned char *frag, *fsize;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000705 char buf[80];
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000706 int os = current_fs->super->s_creator_os;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000707 const char *hex_format = "0x%x";
708 const char *octal_format = "0%o";
709 const char *decimal_format = "%d";
Theodore Ts'o3839e651997-04-26 13:21:57 +0000710
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;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000717 if (check_fs_read_write(argv[0]))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000718 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000719
720 inode_num = string_to_inode(argv[1]);
721 if (!inode_num)
722 return;
723
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000724 retval = ext2fs_read_inode(current_fs, inode_num, &inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000725 if (retval) {
726 com_err(argv[1], retval, "while trying to read inode %d",
727 inode_num);
728 return;
729 }
730
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000731 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);
Theodore Ts'o36a43d61998-03-24 16:17:51 +0000746 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);
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000750
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000751 if (current_fs->super->s_creator_os == EXT2_OS_HURD)
Theodore Ts'o62c06f71997-04-29 14:34:47 +0000752 modify_u32(argv[0], "Translator Block",
753 decimal_format, &inode.osd1.hurd1.h_i_translator);
754
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000755 modify_u32(argv[0], "Fragment address", decimal_format, &inode.i_faddr);
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000756 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
Theodore Ts'o3839e651997-04-26 13:21:57 +0000777 for (i=0; i < EXT2_NDIR_BLOCKS; i++) {
778 sprintf(buf, "Direct Block #%d", i);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000779 modify_u32(argv[0], buf, decimal_format, &inode.i_block[i]);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000780 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000781 modify_u32(argv[0], "Indirect Block", decimal_format,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000782 &inode.i_block[EXT2_IND_BLOCK]);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000783 modify_u32(argv[0], "Double Indirect Block", decimal_format,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000784 &inode.i_block[EXT2_DIND_BLOCK]);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000785 modify_u32(argv[0], "Triple Indirect Block", decimal_format,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000786 &inode.i_block[EXT2_TIND_BLOCK]);
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000787 retval = ext2fs_write_inode(current_fs, inode_num, &inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000788 if (retval) {
789 com_err(argv[1], retval, "while trying to write inode %d",
790 inode_num);
791 return;
792 }
793}
794
Theodore Ts'o3839e651997-04-26 13:21:57 +0000795void 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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000811 retval = ext2fs_check_directory(current_fs, inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000812 if (retval) {
813 com_err(argv[1], retval, "");
814 return;
815 }
816 cwd = inode;
817 return;
818}
819
Theodore Ts'o3839e651997-04-26 13:21:57 +0000820void 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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000832 retval = ext2fs_get_pathname(current_fs, cwd, 0, &pathname);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000833 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);
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000839 retval = ext2fs_get_pathname(current_fs, root, 0, &pathname);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000840 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
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000849static void make_link(char *sourcename, char *destname)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000850{
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 */
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000871 if (! (retval=ext2fs_namei(current_fs, root, cwd, destname, &dir)))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000872 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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000891 retval = ext2fs_link(current_fs, dir, dest, inode, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000892 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
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000910static void unlink_file_by_name(char *filename)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000911{
912 int retval;
913 ino_t dir;
914 char *basename;
915
916 basename = strrchr(filename, '/');
917 if (basename) {
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000918 *basename++ = '\0';
Theodore Ts'o3839e651997-04-26 13:21:57 +0000919 dir = string_to_inode(filename);
920 if (!dir)
921 return;
922 } else {
923 dir = cwd;
924 basename = filename;
925 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000926 retval = ext2fs_unlink(current_fs, dir, basename, 0, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000927 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
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000950 if ((argc > 2) || (argc==2 && *argv[1] == '?')) {
951 com_err(argv[0], 0, "Usage: find_free_block [goal]");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000952 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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000965 goal = current_fs->super->s_first_data_block;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000966
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +0000967 retval = ext2fs_new_block(current_fs, goal, 0, &free_blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000968 if (retval)
969 com_err("ext2fs_new_block", retval, "");
970 else
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000971 printf("Free block found: %d\n", free_blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000972
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
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000982 if (argc > 3 || (argc>1 && *argv[1] == '?')) {
983 com_err(argv[0], 0, "Usage: find_free_inode [dir] [mode]");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000984 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 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001004 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +00001005 mode = 010755;
1006
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001007 retval = ext2fs_new_inode(current_fs, dir, mode, 0, &free_inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001008 if (retval)
1009 com_err("ext2fs_new_inode", retval, "");
1010 else
1011 printf("Free inode found: %ld\n", free_inode);
1012}
1013
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001014static errcode_t copy_file(int fd, ino_t newfile)
1015{
Theodore Ts'o5a513841997-10-25 22:41:14 +00001016 ext2_file_t e2_file;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001017 errcode_t retval;
Theodore Ts'o4a31c481998-03-30 01:27:25 +00001018 unsigned int got, written;
Theodore Ts'o5a513841997-10-25 22:41:14 +00001019 char buf[8192];
1020 char *ptr;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001021
Theodore Ts'o5a513841997-10-25 22:41:14 +00001022 retval = ext2fs_file_open(current_fs, newfile,
1023 EXT2_FILE_WRITE, &e2_file);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001024 if (retval)
1025 return retval;
1026
Theodore Ts'o5a513841997-10-25 22:41:14 +00001027 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);
1047
1048 return retval;
1049
1050fail:
1051 (void) ext2fs_file_close(e2_file);
1052 return retval;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001053}
1054
Theodore Ts'o5a513841997-10-25 22:41:14 +00001055
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001056void 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;
Theodore Ts'o5a513841997-10-25 22:41:14 +00001063 dgrp_t group;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001064
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 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001071 if (check_fs_read_write(argv[0]))
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001072 return;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001073 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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001084 retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001085 if (retval) {
1086 com_err(argv[0], retval, "");
1087 close(fd);
1088 return;
1089 }
Theodore Ts'o5a513841997-10-25 22:41:14 +00001090 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);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001094 printf("Allocated inode: %ld\n", newfile);
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001095 retval = ext2fs_link(current_fs, cwd, argv[2], newfile, 0);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001096 if (retval) {
1097 com_err(argv[2], retval, "");
1098 close(fd);
1099 return;
1100 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001101 if (ext2fs_test_inode_bitmap(current_fs->inode_map,newfile))
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001102 com_err(argv[0], 0, "Warning: inode already set");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001103 ext2fs_mark_inode_bitmap(current_fs->inode_map,newfile);
1104 ext2fs_mark_ib_dirty(current_fs);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001105 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;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001110 ext2fs_write_inode(current_fs, newfile, &inode);
1111 retval = ext2fs_write_inode(current_fs, newfile, &inode);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001112 if (retval) {
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001113 com_err(argv[0], retval, "while trying to write inode %d",
1114 inode);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001115 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 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001166 if (check_fs_read_write(argv[0]))
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001167 return;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001168 retval = ext2fs_new_inode(current_fs, cwd, 010755, 0, &newfile);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001169 if (retval) {
1170 com_err(argv[0], retval, "");
1171 return;
1172 }
1173 printf("Allocated inode: %ld\n", newfile);
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001174 retval = ext2fs_link(current_fs, cwd, argv[1], newfile, 0);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001175 if (retval) {
1176 if (retval == EXT2_ET_DIR_NO_SPACE) {
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001177 retval = ext2fs_expand_dir(current_fs, cwd);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001178 if (!retval)
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001179 retval = ext2fs_link(current_fs, cwd,
1180 argv[1], newfile, 0);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001181 }
1182 if (retval) {
1183 com_err(argv[1], retval, "");
1184 return;
1185 }
1186 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001187 if (ext2fs_test_inode_bitmap(current_fs->inode_map,newfile))
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001188 com_err(argv[0], 0, "Warning: inode already set");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001189 ext2fs_mark_inode_bitmap(current_fs->inode_map, newfile);
1190 ext2fs_mark_ib_dirty(current_fs);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001191 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;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001196 ext2fs_write_inode(current_fs, newfile, &inode);
1197 retval = ext2fs_write_inode(current_fs, newfile, &inode);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001198 if (retval) {
1199 com_err(argv[0], retval, "while trying to write inode %d", inode);
1200 return;
1201 }
1202}
1203
Theodore Ts'o3839e651997-04-26 13:21:57 +00001204void 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
Theodore Ts'od3aea7d1999-09-14 20:55:37 +00001219 if (check_fs_read_write(argv[0]))
1220 return;
1221
Theodore Ts'o3839e651997-04-26 13:21:57 +00001222 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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001237 retval = ext2fs_mkdir(current_fs, parent, 0, name);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001238 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
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001251static int release_blocks_proc(ext2_filsys fs, blk_t *blocknr,
1252 int blockcnt, void *private)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001253{
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001254 printf("%d ", *blocknr);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001255 ext2fs_unmark_block_bitmap(fs->block_map,*blocknr);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001256 return 0;
1257}
1258
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001259static void kill_file_by_inode(ino_t inode)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001260{
1261 struct ext2_inode inode_buf;
1262
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001263 ext2fs_read_inode(current_fs, inode, &inode_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001264 inode_buf.i_dtime = time(NULL);
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001265 ext2fs_write_inode(current_fs, inode, &inode_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001266
1267 printf("Kill file by inode %ld\n", inode);
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001268 ext2fs_block_iterate(current_fs, inode, 0, NULL,
1269 release_blocks_proc, NULL);
Theodore Ts'o521e3681997-04-29 17:48:10 +00001270 printf("\n");
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001271 ext2fs_unmark_inode_bitmap(current_fs->inode_map, inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001272
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001273 ext2fs_mark_bb_dirty(current_fs);
1274 ext2fs_mark_ib_dirty(current_fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001275}
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
Theodore Ts'od3aea7d1999-09-14 20:55:37 +00001289 if (check_fs_read_write(argv[0]))
1290 return;
1291
Theodore Ts'o3839e651997-04-26 13:21:57 +00001292 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
Theodore Ts'od3aea7d1999-09-14 20:55:37 +00001313 if (check_fs_read_write(argv[0]))
1314 return;
1315
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001316 retval = ext2fs_namei(current_fs, root, cwd, argv[1], &inode_num);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001317 if (retval) {
Theodore Ts'o91d6d481998-08-01 01:03:39 +00001318 com_err(argv[0], retval, "while trying to resolve filename");
Theodore Ts'o3839e651997-04-26 13:21:57 +00001319 return;
1320 }
1321
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001322 retval = ext2fs_read_inode(current_fs,inode_num,&inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001323 if (retval) {
1324 com_err(argv[0], retval, "while reading file's inode");
1325 return;
1326 }
1327
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001328 if (LINUX_S_ISDIR(inode.i_mode)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +00001329 com_err(argv[0], 0, "file is a directory");
1330 return;
1331 }
1332
1333 --inode.i_links_count;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001334 retval = ext2fs_write_inode(current_fs,inode_num,&inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001335 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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001349 if (current_fs)
1350 fprintf(out, "Open mode: read-%s\n",
1351 current_fs->flags & EXT2_FLAG_RW ? "write" : "only");
Theodore Ts'o3839e651997-04-26 13:21:57 +00001352 fprintf(out, "Filesystem in use: %s\n",
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001353 current_fs ? current_fs->device_name : "--none--");
Theodore Ts'o3839e651997-04-26 13:21:57 +00001354}
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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001371 retval = ext2fs_expand_dir(current_fs, inode);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001372 if (retval)
1373 com_err("ext2fs_expand_dir", retval, "");
1374 return;
1375}
1376
Theodore Ts'od3aea7d1999-09-14 20:55:37 +00001377void 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],
1388 &current_fs->super->s_feature_compat))
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
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001397static 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
Theodore Ts'oa8859ca1997-09-16 02:08:28 +00001435int main(int argc, char **argv)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001436{
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001437 int retval;
1438 int sci_idx;
Theodore Ts'o818180c1998-06-27 05:11:14 +00001439 const char *usage = "Usage: debugfs [-f cmd_file] [-R request] [-V] [[-w] device]";
Theodore Ts'of1304811997-10-25 03:51:53 +00001440 int c;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001441 int open_flags = 0;
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001442 char *request = 0;
1443 int exit_status = 0;
1444 char *cmd_file = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001445
1446 initialize_ext2_error_table();
Theodore Ts'o818180c1998-06-27 05:11:14 +00001447 fprintf (stderr, "debugfs %s, %s for EXT2 FS %s, %s\n",
1448 E2FSPROGS_VERSION, E2FSPROGS_DATE,
1449 EXT2FS_VERSION, EXT2FS_DATE);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001450
Theodore Ts'o818180c1998-06-27 05:11:14 +00001451 while ((c = getopt (argc, argv, "wR:f:V")) != EOF) {
Theodore Ts'o3839e651997-04-26 13:21:57 +00001452 switch (c) {
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001453 case 'R':
1454 request = optarg;
1455 break;
1456 case 'f':
1457 cmd_file = optarg;
1458 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001459 case 'w':
1460 open_flags = EXT2_FLAG_RW;
1461 break;
Theodore Ts'o818180c1998-06-27 05:11:14 +00001462 case 'V':
1463 /* Print version number and exit */
1464 fprintf(stderr, "\tUsing %s\n",
1465 error_message(EXT2_ET_BASE));
1466 exit(0);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001467 default:
1468 com_err(argv[0], 0, usage);
Theodore Ts'ob4ac9cc1997-10-15 01:54:48 +00001469 return 1;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001470 }
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 }
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001487 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 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001499
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001500 if (current_fs)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001501 close_filesystem();
1502
Theodore Ts'ofc6d9d51997-04-29 14:51:31 +00001503 exit(exit_status);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001504}
1505