Whamcloud - gitweb
Add initial support in debugfs for examining directory indexing
[tools/e2fsprogs.git] / debugfs / util.c
1 /*
2  * util.c --- utilities for the debugfs program
3  * 
4  * Copyright (C) 1993, 1994 Theodore Ts'o.  This file may be
5  * redistributed under the terms of the GNU Public License.
6  *
7  */
8
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <string.h>
14 #include <time.h>
15 #include <signal.h>
16
17 #include "debugfs.h"
18
19 FILE *open_pager(void)
20 {
21         FILE *outfile;
22         const char *pager = getenv("PAGER");
23
24         signal(SIGPIPE, SIG_IGN);
25         if (pager) {
26                 if (strcmp(pager, "__none__") == 0) {
27                         return stdout;
28                 }
29         } else
30                 pager = "more";
31
32         outfile = popen(pager, "w");
33
34         return (outfile ? outfile : stdout);
35 }
36
37 void close_pager(FILE *stream)
38 {
39         if (stream && stream != stdout) pclose(stream);
40 }
41
42 /*
43  * This routine is used whenever a command needs to turn a string into
44  * an inode.
45  */
46 ext2_ino_t string_to_inode(char *str)
47 {
48         ext2_ino_t      ino;
49         int             len = strlen(str);
50         char            *end;
51         int             retval;
52
53         /*
54          * If the string is of the form <ino>, then treat it as an
55          * inode number.
56          */
57         if ((len > 2) && (str[0] == '<') && (str[len-1] == '>')) {
58                 ino = strtoul(str+1, &end, 0);
59                 if (*end=='>')
60                         return ino;
61         }
62
63         retval = ext2fs_namei(current_fs, root, cwd, str, &ino);
64         if (retval) {
65                 com_err(str, retval, "");
66                 return 0;
67         }
68         return ino;
69 }
70
71 /*
72  * This routine returns 1 if the filesystem is not open, and prints an
73  * error message to that effect.
74  */
75 int check_fs_open(char *name)
76 {
77         if (!current_fs) {
78                 com_err(name, 0, "Filesystem not open");
79                 return 1;
80         }
81         return 0;
82 }
83
84 /*
85  * This routine returns 1 if a filesystem is open, and prints an
86  * error message to that effect.
87  */
88 int check_fs_not_open(char *name)
89 {
90         if (current_fs) {
91                 com_err(name, 0,
92                         "Filesystem %s is still open.  Close it first.\n",
93                         current_fs->device_name);
94                 return 1;
95         }
96         return 0;
97 }
98
99 /*
100  * This routine returns 1 if a filesystem is not opened read/write,
101  * and prints an error message to that effect.
102  */
103 int check_fs_read_write(char *name)
104 {
105         if (!(current_fs->flags & EXT2_FLAG_RW)) {
106                 com_err(name, 0, "Filesystem opened read/only");
107                 return 1;
108         }
109         return 0;
110 }
111
112 /*
113  * This routine returns 1 if a filesystem is doesn't have its inode
114  * and block bitmaps loaded, and prints an error message to that
115  * effect.
116  */
117 int check_fs_bitmaps(char *name)
118 {
119         if (!current_fs->block_map || !current_fs->inode_map) {
120                 com_err(name, 0, "Filesystem bitmaps not loaded");
121                 return 1;
122         }
123         return 0;
124 }
125
126 /*
127  * This function takes a __u32 time value and converts it to a string,
128  * using ctime
129  */
130 char *time_to_string(__u32 cl)
131 {
132         time_t  t = (time_t) cl;
133
134         return ctime(&t);
135 }
136
137 /*
138  * This function will convert a string to an unsigned long, printing
139  * an error message if it fails, and returning success or failure in err.
140  */
141 unsigned long parse_ulong(const char *str, const char *cmd,
142                           const char *descr, int *err)
143 {
144         char            *tmp;
145         unsigned long   ret;
146         
147         ret = strtoul(str, &tmp, 0);
148         if (*tmp == 0) {
149                 if (*err)
150                         *err = 0;
151                 return ret;
152         }
153         com_err(cmd, 0, "Bad %s - %s", descr, str);
154         if (*err)
155                 *err = 1;
156         else
157                 exit(1);
158         return 0;
159 }
160
161 /*
162  * This function will convert a string to a block number.  It returns
163  * 0 on success, 1 on failure.
164  */
165 int strtoblk(const char *cmd, const char *str, blk_t *ret)
166 {
167         blk_t   blk;
168         int     err;
169
170         blk = parse_ulong(str, cmd, "block number", &err);
171         *ret = blk;
172         if (err == 0 && blk == 0) {
173                 com_err(cmd, 0, "Invalid block number 0");
174                 err = 1;
175         }
176         return err;
177 }
178
179 /*
180  * This is a common helper function used by the command processing
181  * routines
182  */
183 int common_args_process(int argc, char *argv[], int min_argc, int max_argc,
184                         const char *cmd, const char *usage, int flags)
185 {
186         if (argc < min_argc || argc > max_argc) {
187                 com_err(argv[0], 0, "Usage: %s %s", cmd, usage);
188                 return 1;
189         }
190         if (flags & CHECK_FS_NOTOPEN) {
191                 if (check_fs_not_open(argv[0]))
192                         return 1;
193         } else {
194                 if (check_fs_open(argv[0]))
195                         return 1;
196         }
197         if ((flags & CHECK_FS_RW) && check_fs_read_write(argv[0]))
198                 return 1;
199         if ((flags & CHECK_FS_BITMAPS) && check_fs_bitmaps(argv[0]))
200                 return 1;
201         return 0;
202 }
203
204 /*
205  * This is a helper function used by do_stat, do_freei, do_seti, and
206  * do_testi, etc.  Basically, any command which takes a single
207  * argument which is a file/inode number specifier.
208  */
209 int common_inode_args_process(int argc, char *argv[],
210                               ext2_ino_t *inode, int flags)
211 {
212         if (common_args_process(argc, argv, 2, 2, argv[0], "<file>", flags))
213                 return 1;
214         
215         *inode = string_to_inode(argv[1]);
216         if (!*inode) 
217                 return 1;
218         return 0;
219 }
220
221 /*
222  * This is a helper function used by do_freeb, do_setb, and do_testb
223  */
224 int common_block_args_process(int argc, char *argv[],
225                               blk_t *block, int *count)
226 {
227         int     err;
228
229         if (common_args_process(argc, argv, 2, 3, argv[0],
230                                 "<block> [count]", CHECK_FS_BITMAPS))
231                 return 1;
232
233         if (strtoblk(argv[0], argv[1], block))
234                 return 1;
235         if (argc > 2) {
236                 *count = parse_ulong(argv[0], argv[2], "count", &err);
237                 if (err)
238                         return 1;
239         }
240         return 0;
241 }
242
243 int debugfs_read_inode(ext2_ino_t ino, struct ext2_inode * inode,
244                         const char *cmd)
245 {
246         int retval;
247
248         retval = ext2fs_read_inode(current_fs, ino, inode);
249         if (retval) {
250                 com_err(cmd, retval, "while reading inode %u", ino);
251                 return 1;
252         }
253         return 0;
254 }
255
256 int debugfs_write_inode(ext2_ino_t ino, struct ext2_inode * inode,
257                         const char *cmd)
258 {
259         int retval;
260
261         retval = ext2fs_write_inode(current_fs, ino, inode);
262         if (retval) {
263                 com_err(cmd, retval, "while writing inode %u", ino);
264                 return 1;
265         }
266         return 0;
267 }
268