source: mainline/uspace/app/ext2info/ext2info.c@ ad34feb

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since ad34feb was ad34feb, checked in by Martin Sucha <sucha14@…>, 15 years ago

Implement reading of blocks from inode in libext2

  • Property mode set to 100644
File size: 12.9 KB
Line 
1/*
2 * Copyright (c) 2011 Martin Sucha
3 * Copyright (c) 2010 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup fs
31 * @{
32 */
33
34/**
35 * @file ext2info.c
36 * @brief Tool for displaying information about ext2 filesystem
37 *
38 */
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <libblock.h>
43#include <mem.h>
44#include <devmap.h>
45#include <byteorder.h>
46#include <sys/types.h>
47#include <sys/typefmt.h>
48#include <inttypes.h>
49#include <errno.h>
50#include <libext2.h>
51
52#define NAME "ext2info"
53
54static void syntax_print(void);
55static void print_superblock(ext2_superblock_t *);
56static void print_block_groups(ext2_filesystem_t *);
57static void print_block_group(ext2_block_group_t *);
58static void print_inode_by_number(ext2_filesystem_t *, uint32_t, bool, uint32_t);
59static void print_inode(ext2_filesystem_t *, ext2_inode_t *);
60static void print_inode_data(ext2_filesystem_t *, ext2_inode_t *, uint32_t);
61
62#define ARG_SUPERBLOCK 1
63#define ARG_BLOCK_GROUPS 2
64#define ARG_INODE 4
65#define ARG_STRICT_CHECK 8
66#define ARG_INODE_DATA 16
67#define ARG_COMMON (ARG_SUPERBLOCK | ARG_BLOCK_GROUPS)
68#define ARG_ALL (ARG_COMMON | ARG_INODE)
69
70
71int main(int argc, char **argv)
72{
73
74 int rc;
75 char *endptr;
76 char *dev_path;
77 devmap_handle_t handle;
78 ext2_filesystem_t filesystem;
79 int arg_flags;
80 uint32_t inode = 0;
81 uint32_t inode_data = 0;
82
83 arg_flags = 0;
84
85 if (argc < 2) {
86 printf(NAME ": Error, argument missing.\n");
87 syntax_print();
88 return 1;
89 }
90
91 // Skip program name
92 --argc; ++argv;
93
94 if (str_cmp(*argv, "--strict-check") == 0) {
95 --argc; ++argv;
96 arg_flags |= ARG_STRICT_CHECK;
97 }
98
99 if (str_cmp(*argv, "--superblock") == 0) {
100 --argc; ++argv;
101 arg_flags |= ARG_SUPERBLOCK;
102 }
103
104 if (str_cmp(*argv, "--block-groups") == 0) {
105 --argc; ++argv;
106 arg_flags |= ARG_BLOCK_GROUPS;
107 }
108
109 if (str_cmp(*argv, "--inode") == 0) {
110 --argc; ++argv;
111 if (argc == 0) {
112 printf(NAME ": Argument expected for --inode\n");
113 return 2;
114 }
115
116 inode = strtol(*argv, &endptr, 10);
117 if (*endptr != '\0') {
118 printf(NAME ": Error, invalid argument for --inode.\n");
119 syntax_print();
120 return 1;
121 }
122
123 arg_flags |= ARG_INODE;
124 --argc; ++argv;
125
126 if (str_cmp(*argv, "--inode-data") == 0) {
127 --argc; ++argv;
128 if (argc == 0) {
129 printf(NAME ": Argument expected for --inode-data\n");
130 return 2;
131 }
132
133 inode_data = strtol(*argv, &endptr, 10);
134 if (*endptr != '\0') {
135 printf(NAME ": Error, invalid argument for --inode-data.\n");
136 syntax_print();
137 return 1;
138 }
139
140 arg_flags |= ARG_INODE_DATA;
141 --argc; ++argv;
142 }
143 }
144
145 if (argc != 1) {
146 printf(NAME ": Error, unexpected argument.\n");
147 syntax_print();
148 return 1;
149 }
150
151 // Display common things by default
152 if ((arg_flags & ARG_ALL) == 0) {
153 arg_flags = ARG_COMMON;
154 }
155
156 dev_path = *argv;
157
158 rc = devmap_device_get_handle(dev_path, &handle, 0);
159 if (rc != EOK) {
160 printf(NAME ": Error resolving device `%s'.\n", dev_path);
161 return 2;
162 }
163
164 rc = ext2_filesystem_init(&filesystem, handle);
165 if (rc != EOK) {
166 printf(NAME ": Error initializing libext2.\n");
167 return 3;
168 }
169
170 rc = ext2_filesystem_check_sanity(&filesystem);
171 if (rc != EOK) {
172 printf(NAME ": Filesystem did not pass sanity check.\n");
173 if (arg_flags & ARG_STRICT_CHECK) {
174 return 3;
175 }
176 }
177
178 if (arg_flags & ARG_SUPERBLOCK) {
179 print_superblock(filesystem.superblock);
180 }
181
182 if (arg_flags & ARG_BLOCK_GROUPS) {
183 print_block_groups(&filesystem);
184 }
185
186 if (arg_flags & ARG_INODE) {
187 print_inode_by_number(&filesystem, inode, arg_flags & ARG_INODE_DATA,
188 inode_data);
189 }
190
191 ext2_filesystem_fini(&filesystem);
192
193 return 0;
194}
195
196
197static void syntax_print(void)
198{
199 printf("syntax: ext2info [--strict-check] [--superblock] [--block-groups] "
200 "[--inode <i-number> [--inode-data <block-number>]] <device_name>\n");
201}
202
203static void print_superblock(ext2_superblock_t *superblock)
204{
205 uint16_t magic;
206 uint32_t first_block;
207 uint32_t block_size;
208 uint32_t fragment_size;
209 uint32_t blocks_per_group;
210 uint32_t fragments_per_group;
211 uint32_t rev_major;
212 uint16_t rev_minor;
213 uint16_t state;
214 uint32_t first_inode;
215 uint16_t inode_size;
216 uint32_t total_blocks;
217 uint32_t reserved_blocks;
218 uint32_t free_blocks;
219 uint32_t total_inodes;
220 uint32_t free_inodes;
221 uint32_t os;
222
223 int pos;
224 unsigned char c;
225
226 magic = ext2_superblock_get_magic(superblock);
227 first_block = ext2_superblock_get_first_block(superblock);
228 block_size = ext2_superblock_get_block_size(superblock);
229 fragment_size = ext2_superblock_get_fragment_size(superblock);
230 blocks_per_group = ext2_superblock_get_blocks_per_group(superblock);
231 fragments_per_group = ext2_superblock_get_fragments_per_group(superblock);
232 rev_major = ext2_superblock_get_rev_major(superblock);
233 rev_minor = ext2_superblock_get_rev_minor(superblock);
234 state = ext2_superblock_get_state(superblock);
235 first_inode = ext2_superblock_get_first_inode(superblock);
236 inode_size = ext2_superblock_get_inode_size(superblock);
237 total_blocks = ext2_superblock_get_total_block_count(superblock);
238 reserved_blocks = ext2_superblock_get_reserved_block_count(superblock);
239 free_blocks = ext2_superblock_get_free_block_count(superblock);
240 total_inodes = ext2_superblock_get_total_inode_count(superblock);
241 free_inodes = ext2_superblock_get_free_inode_count(superblock);
242 os = ext2_superblock_get_os(superblock);
243
244 printf("Superblock:\n");
245
246 if (magic == EXT2_SUPERBLOCK_MAGIC) {
247 printf(" Magic value: %X (correct)\n", magic);
248 }
249 else {
250 printf(" Magic value: %X (incorrect)\n", magic);
251 }
252
253 printf(" Revision: %u.%hu\n", rev_major, rev_minor);
254 printf(" State: %hu\n", state);
255 printf(" Creator OS: %u\n", os);
256 printf(" First block: %u\n", first_block);
257 printf(" Block size: %u bytes (%u KiB)\n", block_size, block_size/1024);
258 printf(" Blocks per group: %u\n", blocks_per_group);
259 printf(" Total blocks: %u\n", total_blocks);
260 printf(" Reserved blocks: %u\n", reserved_blocks);
261 printf(" Free blocks: %u\n", free_blocks);
262 printf(" Fragment size: %u bytes (%u KiB)\n", fragment_size,
263 fragment_size/1024);
264 printf(" Fragments per group: %u\n", fragments_per_group);
265 printf(" First inode: %u\n", first_inode);
266 printf(" Inode size: %hu bytes\n", inode_size);
267 printf(" Total inodes: %u\n", total_inodes);
268 printf(" Free inodes: %u\n", free_inodes);
269
270
271 if (rev_major == 1) {
272 printf(" UUID: ");
273 for (pos = 0; pos < 16; pos++) {
274 printf("%02x", superblock->uuid[pos]);
275 }
276 printf("\n");
277
278 printf(" Volume label: ");
279 for (pos = 0; pos < 16; pos++) {
280 c = superblock->volume_name[pos];
281 if (c >= 32 && c < 128) {
282 putchar(c);
283 }
284 else {
285 putchar(' ');
286 }
287 }
288 printf("\n");
289 }
290
291}
292
293void print_block_groups(ext2_filesystem_t *filesystem)
294{
295 uint32_t block_group_count;
296 uint32_t i;
297 ext2_block_group_ref_t *block_group_ref;
298 int rc;
299
300 printf("Block groups:\n");
301
302 block_group_count = ext2_superblock_get_block_group_count(
303 filesystem->superblock);
304
305 for (i = 0; i < block_group_count; i++) {
306 printf(" Block group %u\n", i);
307 rc = ext2_filesystem_get_block_group_ref(filesystem, i, &block_group_ref);
308 if (rc != EOK) {
309 printf(" Failed reading block group\n");
310 continue;
311 }
312
313 print_block_group(block_group_ref->block_group);
314
315 rc = ext2_filesystem_put_block_group_ref(block_group_ref);
316 if (rc != EOK) {
317 printf(" Failed freeing block group\n");
318 }
319 }
320
321}
322
323void print_block_group(ext2_block_group_t *bg)
324{
325 uint32_t block_bitmap_block;
326 uint32_t inode_bitmap_block;
327 uint32_t inode_table_first_block;
328 uint16_t free_block_count;
329 uint16_t free_inode_count;
330 uint16_t directory_inode_count;
331
332 block_bitmap_block = ext2_block_group_get_block_bitmap_block(bg);
333 inode_bitmap_block = ext2_block_group_get_inode_bitmap_block(bg);
334 inode_table_first_block = ext2_block_group_get_inode_table_first_block(bg);
335 free_block_count = ext2_block_group_get_free_block_count(bg);
336 free_inode_count = ext2_block_group_get_free_inode_count(bg);
337 directory_inode_count = ext2_block_group_get_directory_inode_count(bg);
338
339 printf(" Block bitmap block: %u\n", block_bitmap_block);
340 printf(" Inode bitmap block: %u\n", inode_bitmap_block);
341 printf(" Inode table's first block: %u\n", inode_table_first_block);
342 printf(" Free blocks: %u\n", free_block_count);
343 printf(" Free inodes: %u\n", free_inode_count);
344 printf(" Directory inodes: %u\n", directory_inode_count);
345}
346
347void print_inode_by_number(ext2_filesystem_t *fs, uint32_t inode,
348 bool print_data, uint32_t data)
349{
350 int rc;
351 ext2_inode_ref_t *inode_ref;
352
353 printf("Inode %u\n", inode);
354
355 rc = ext2_filesystem_get_inode_ref(fs, inode, &inode_ref);
356 if (rc != EOK) {
357 printf(" Failed getting inode ref\n");
358 return;
359 }
360
361 print_inode(fs, inode_ref->inode);
362 if (print_data) {
363 print_inode_data(fs, inode_ref->inode, data);
364 }
365
366 rc = ext2_filesystem_put_inode_ref(inode_ref);
367 if (rc != EOK) {
368 printf(" Failed putting inode ref\n");
369 }
370}
371
372void print_inode(ext2_filesystem_t *fs, ext2_inode_t *inode)
373{
374 uint32_t mode;
375 uint32_t mode_type;
376 uint32_t user_id;
377 uint32_t group_id;
378 uint64_t size;
379 uint16_t usage_count;
380 uint32_t flags;
381 uint16_t access;
382 const char *type;
383 uint32_t block;
384 uint32_t total_blocks;
385 int i;
386 bool all_blocks = false;
387
388 mode = ext2_inode_get_mode(fs->superblock, inode);
389 mode_type = mode & EXT2_INODE_MODE_TYPE_MASK;
390 user_id = ext2_inode_get_user_id(fs->superblock, inode);
391 group_id = ext2_inode_get_group_id(fs->superblock, inode);
392 size = ext2_inode_get_size(fs->superblock, inode);
393 usage_count = ext2_inode_get_usage_count(inode);
394 flags = ext2_inode_get_flags(inode);
395 total_blocks = ext2_inode_get_reserved_blocks(fs->superblock, inode);
396
397 type = "Unknown";
398 if (mode_type == EXT2_INODE_MODE_BLOCKDEV) {
399 type = "Block device";
400 }
401 else if (mode_type == EXT2_INODE_MODE_FIFO) {
402 type = "Fifo (pipe)";
403 }
404 else if (mode_type == EXT2_INODE_MODE_CHARDEV) {
405 type = "Character device";
406 }
407 else if (mode_type == EXT2_INODE_MODE_DIRECTORY) {
408 type = "Directory";
409 }
410 else if (mode_type == EXT2_INODE_MODE_FILE) {
411 type = "File";
412 }
413 else if (mode_type == EXT2_INODE_MODE_SOFTLINK) {
414 type = "Soft link";
415 }
416 else if (mode_type == EXT2_INODE_MODE_SOCKET) {
417 type = "Socket";
418 }
419
420 access = mode & EXT2_INODE_MODE_ACCESS_MASK;
421
422
423 printf(" Mode: %08x (Type: %s, Access bits: %04ho)\n", mode, type, access);
424 printf(" User ID: %u\n", user_id);
425 printf(" Group ID: %u\n", group_id);
426 printf(" Size: %" PRIu64 "\n", size);
427 printf(" Usage (link) count: %u\n", usage_count);
428 printf(" Flags: %u\n", flags);
429 printf(" Total allocated blocks: %u\n", total_blocks);
430 printf(" Block list: ");
431 for (i = 0; i < 12; i++) {
432 block = ext2_inode_get_direct_block(inode, i);
433 if (block == 0) {
434 all_blocks = true;
435 break;
436 }
437 printf("%u ", block);
438 }
439 all_blocks = all_blocks || ext2_inode_get_indirect_block(inode, 0) == 0;
440 if (!all_blocks) {
441 printf(" and more...");
442 }
443 printf("\n");
444}
445
446void print_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t data)
447{
448 int rc;
449 uint32_t data_block_index;
450 block_t *block;
451 size_t i;
452 unsigned char c;
453
454 rc = ext2_filesystem_get_inode_data_block_index(fs, inode, data,
455 &data_block_index);
456
457 if (rc != EOK) {
458 printf("Failed getting data block #%u\n", data);
459 return;
460 }
461
462 printf("Data for inode contents block #%u is located in filesystem "
463 "block %u\n", data, data_block_index);
464
465 printf("Data preview (only printable characters):\n");
466
467 rc = block_get(&block, fs->device, data_block_index, 0);
468 if (rc != EOK) {
469 printf("Failed reading filesystem block %u\n", data_block_index);
470 return;
471 }
472
473 for (i = 0; i < block->size; i++) {
474 c = ((unsigned char *)block->data)[i];
475 if (c >= 32 && c < 127) {
476 putchar(c);
477 }
478 else {
479 putchar('.');
480 }
481 }
482
483 printf("\n");
484
485 rc = block_put(block);
486 if (rc != EOK) {
487 printf("Failed putting filesystem block\n");
488 }
489
490}
491
492/**
493 * @}
494 */
Note: See TracBrowser for help on using the repository browser.