source: mainline/uspace/app/ext2info/ext2info.c@ 1a86c50

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

Coding style and comments

  • Property mode set to 100644
File size: 15.8 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#include <assert.h>
52
53#define NAME "ext2info"
54
55static void syntax_print(void);
56static void print_superblock(ext2_superblock_t *);
57static void print_block_groups(ext2_filesystem_t *);
58static void print_block_group(ext2_block_group_t *);
59static void print_inode_by_number(ext2_filesystem_t *, uint32_t, bool, uint32_t,
60 bool, bool);
61static void print_data(unsigned char *, size_t);
62static void print_inode(ext2_filesystem_t *, ext2_inode_t *, bool);
63static void print_inode_data(ext2_filesystem_t *, ext2_inode_t *, uint32_t);
64static void print_directory_contents(ext2_filesystem_t *, ext2_inode_ref_t *);
65
66#define ARG_SUPERBLOCK 1
67#define ARG_BLOCK_GROUPS 2
68#define ARG_INODE 4
69#define ARG_NO_CHECK 8
70#define ARG_INODE_DATA 16
71#define ARG_INODE_LIST 32
72#define ARG_INODE_BLOCKS 64
73#define ARG_COMMON (ARG_SUPERBLOCK)
74#define ARG_ALL 127
75
76
77int main(int argc, char **argv)
78{
79
80 int rc;
81 char *endptr;
82 char *dev_path;
83 devmap_handle_t handle;
84 ext2_filesystem_t filesystem;
85 int arg_flags;
86 uint32_t inode = 0;
87 uint32_t inode_data = 0;
88
89 arg_flags = 0;
90
91 if (argc < 2) {
92 printf(NAME ": Error, argument missing.\n");
93 syntax_print();
94 return 1;
95 }
96
97 /* Skip program name */
98 --argc; ++argv;
99
100 if (argc > 0 && str_cmp(*argv, "--no-check") == 0) {
101 --argc; ++argv;
102 arg_flags |= ARG_NO_CHECK;
103 }
104
105 if (argc > 0 && str_cmp(*argv, "--superblock") == 0) {
106 --argc; ++argv;
107 arg_flags |= ARG_SUPERBLOCK;
108 }
109
110 if (argc > 0 && str_cmp(*argv, "--block-groups") == 0) {
111 --argc; ++argv;
112 arg_flags |= ARG_BLOCK_GROUPS;
113 }
114
115 if (argc > 0 && str_cmp(*argv, "--inode") == 0) {
116 --argc; ++argv;
117 if (argc == 0) {
118 printf(NAME ": Argument expected for --inode\n");
119 return 2;
120 }
121
122 inode = strtol(*argv, &endptr, 10);
123 if (*endptr != '\0') {
124 printf(NAME ": Error, invalid argument for --inode.\n");
125 syntax_print();
126 return 1;
127 }
128
129 arg_flags |= ARG_INODE;
130 --argc; ++argv;
131
132 if (argc > 0 && str_cmp(*argv, "--blocks") == 0) {
133 --argc; ++argv;
134 arg_flags |= ARG_INODE_BLOCKS;
135 }
136
137 if (argc > 0 && str_cmp(*argv, "--data") == 0) {
138 --argc; ++argv;
139 if (argc == 0) {
140 printf(NAME ": Argument expected for --data\n");
141 return 2;
142 }
143
144 inode_data = strtol(*argv, &endptr, 10);
145 if (*endptr != '\0') {
146 printf(NAME ": Error, invalid argument for --data.\n");
147 syntax_print();
148 return 1;
149 }
150
151 arg_flags |= ARG_INODE_DATA;
152 --argc; ++argv;
153 }
154
155 if (argc > 0 && str_cmp(*argv, "--list") == 0) {
156 --argc; ++argv;
157 arg_flags |= ARG_INODE_LIST;
158 }
159 }
160
161 if (argc < 1) {
162 printf(NAME ": Error, argument missing.\n");
163 syntax_print();
164 return 1;
165 }
166 else if (argc > 1) {
167 printf(NAME ": Error, unexpected argument.\n");
168 syntax_print();
169 return 1;
170 }
171 assert(argc == 1);
172
173 /* Display common things by default */
174 if ((arg_flags & ARG_ALL) == 0) {
175 arg_flags = ARG_COMMON;
176 }
177
178 dev_path = *argv;
179
180 rc = devmap_device_get_handle(dev_path, &handle, 0);
181 if (rc != EOK) {
182 printf(NAME ": Error resolving device `%s'.\n", dev_path);
183 return 2;
184 }
185
186 rc = ext2_filesystem_init(&filesystem, handle);
187 if (rc != EOK) {
188 printf(NAME ": Error initializing libext2.\n");
189 return 3;
190 }
191
192 rc = ext2_filesystem_check_sanity(&filesystem);
193 if (rc != EOK) {
194 printf(NAME ": Filesystem did not pass sanity check.\n");
195 if (!(arg_flags & ARG_NO_CHECK)) {
196 return 3;
197 }
198 }
199
200 if (arg_flags & ARG_SUPERBLOCK) {
201 print_superblock(filesystem.superblock);
202 }
203
204 if (arg_flags & ARG_BLOCK_GROUPS) {
205 print_block_groups(&filesystem);
206 }
207
208 if (arg_flags & ARG_INODE) {
209 print_inode_by_number(&filesystem, inode, arg_flags & ARG_INODE_DATA,
210 inode_data, arg_flags & ARG_INODE_LIST,
211 arg_flags & ARG_INODE_BLOCKS);
212 }
213
214 ext2_filesystem_fini(&filesystem);
215
216 return 0;
217}
218
219
220static void syntax_print(void)
221{
222 printf("syntax: ext2info [--no-check] [--superblock] [--block-groups] "
223 "[--inode <i-number> [--blocks] [--data <block-number>] [--list]] "
224 "<device_name>\n");
225}
226
227static void print_superblock(ext2_superblock_t *superblock)
228{
229 uint16_t magic;
230 uint32_t first_block;
231 uint32_t block_size;
232 uint32_t fragment_size;
233 uint32_t blocks_per_group;
234 uint32_t fragments_per_group;
235 uint32_t rev_major;
236 uint16_t rev_minor;
237 uint16_t state;
238 uint32_t first_inode;
239 uint16_t inode_size;
240 uint32_t total_blocks;
241 uint32_t reserved_blocks;
242 uint32_t free_blocks;
243 uint32_t total_inodes;
244 uint32_t free_inodes;
245 uint32_t os;
246
247 int pos;
248 unsigned char c;
249
250 magic = ext2_superblock_get_magic(superblock);
251 first_block = ext2_superblock_get_first_block(superblock);
252 block_size = ext2_superblock_get_block_size(superblock);
253 fragment_size = ext2_superblock_get_fragment_size(superblock);
254 blocks_per_group = ext2_superblock_get_blocks_per_group(superblock);
255 fragments_per_group = ext2_superblock_get_fragments_per_group(superblock);
256 rev_major = ext2_superblock_get_rev_major(superblock);
257 rev_minor = ext2_superblock_get_rev_minor(superblock);
258 state = ext2_superblock_get_state(superblock);
259 first_inode = ext2_superblock_get_first_inode(superblock);
260 inode_size = ext2_superblock_get_inode_size(superblock);
261 total_blocks = ext2_superblock_get_total_block_count(superblock);
262 reserved_blocks = ext2_superblock_get_reserved_block_count(superblock);
263 free_blocks = ext2_superblock_get_free_block_count(superblock);
264 total_inodes = ext2_superblock_get_total_inode_count(superblock);
265 free_inodes = ext2_superblock_get_free_inode_count(superblock);
266 os = ext2_superblock_get_os(superblock);
267
268 printf("Superblock:\n");
269
270 if (magic == EXT2_SUPERBLOCK_MAGIC) {
271 printf(" Magic value: %X (correct)\n", magic);
272 }
273 else {
274 printf(" Magic value: %X (incorrect)\n", magic);
275 }
276
277 printf(" Revision: %u.%hu\n", rev_major, rev_minor);
278 printf(" State: %hu\n", state);
279 printf(" Creator OS: %u\n", os);
280 printf(" First block: %u\n", first_block);
281 printf(" Block size: %u bytes (%u KiB)\n", block_size, block_size/1024);
282 printf(" Blocks per group: %u\n", blocks_per_group);
283 printf(" Total blocks: %u\n", total_blocks);
284 printf(" Reserved blocks: %u\n", reserved_blocks);
285 printf(" Free blocks: %u\n", free_blocks);
286 printf(" Fragment size: %u bytes (%u KiB)\n", fragment_size,
287 fragment_size/1024);
288 printf(" Fragments per group: %u\n", fragments_per_group);
289 printf(" First inode: %u\n", first_inode);
290 printf(" Inode size: %hu bytes\n", inode_size);
291 printf(" Total inodes: %u\n", total_inodes);
292 printf(" Free inodes: %u\n", free_inodes);
293
294
295 if (rev_major == 1) {
296 printf(" UUID: ");
297 for (pos = 0; pos < 16; pos++) {
298 printf("%02x", superblock->uuid[pos]);
299 }
300 printf("\n");
301
302 printf(" Volume label: ");
303 for (pos = 0; pos < 16; pos++) {
304 c = superblock->volume_name[pos];
305 if (c >= 32 && c < 128) {
306 putchar(c);
307 }
308 else {
309 putchar(' ');
310 }
311 }
312 printf("\n");
313 }
314
315}
316
317void print_block_groups(ext2_filesystem_t *filesystem)
318{
319 uint32_t block_group_count;
320 uint32_t i;
321 ext2_block_group_ref_t *block_group_ref;
322 int rc;
323
324 printf("Block groups:\n");
325
326 block_group_count = ext2_superblock_get_block_group_count(
327 filesystem->superblock);
328
329 for (i = 0; i < block_group_count; i++) {
330 printf(" Block group %u\n", i);
331 rc = ext2_filesystem_get_block_group_ref(filesystem, i, &block_group_ref);
332 if (rc != EOK) {
333 printf(" Failed reading block group\n");
334 continue;
335 }
336
337 print_block_group(block_group_ref->block_group);
338
339 rc = ext2_filesystem_put_block_group_ref(block_group_ref);
340 if (rc != EOK) {
341 printf(" Failed freeing block group\n");
342 }
343 }
344
345}
346
347void print_block_group(ext2_block_group_t *bg)
348{
349 uint32_t block_bitmap_block;
350 uint32_t inode_bitmap_block;
351 uint32_t inode_table_first_block;
352 uint16_t free_block_count;
353 uint16_t free_inode_count;
354 uint16_t directory_inode_count;
355
356 block_bitmap_block = ext2_block_group_get_block_bitmap_block(bg);
357 inode_bitmap_block = ext2_block_group_get_inode_bitmap_block(bg);
358 inode_table_first_block = ext2_block_group_get_inode_table_first_block(bg);
359 free_block_count = ext2_block_group_get_free_block_count(bg);
360 free_inode_count = ext2_block_group_get_free_inode_count(bg);
361 directory_inode_count = ext2_block_group_get_directory_inode_count(bg);
362
363 printf(" Block bitmap block: %u\n", block_bitmap_block);
364 printf(" Inode bitmap block: %u\n", inode_bitmap_block);
365 printf(" Inode table's first block: %u\n", inode_table_first_block);
366 printf(" Free blocks: %u\n", free_block_count);
367 printf(" Free inodes: %u\n", free_inode_count);
368 printf(" Directory inodes: %u\n", directory_inode_count);
369}
370
371void print_inode_by_number(ext2_filesystem_t *fs, uint32_t inode,
372 bool print_data, uint32_t data, bool list, bool blocks)
373{
374 int rc;
375 ext2_inode_ref_t *inode_ref;
376
377 printf("Inode %u\n", inode);
378
379 rc = ext2_filesystem_get_inode_ref(fs, inode, &inode_ref);
380 if (rc != EOK) {
381 printf(" Failed getting inode ref\n");
382 return;
383 }
384
385 print_inode(fs, inode_ref->inode, blocks);
386 if (print_data) {
387 print_inode_data(fs, inode_ref->inode, data);
388 }
389
390 if (list && ext2_inode_is_type(fs->superblock, inode_ref->inode,
391 EXT2_INODE_MODE_DIRECTORY)) {
392 print_directory_contents(fs, inode_ref);
393 }
394
395 rc = ext2_filesystem_put_inode_ref(inode_ref);
396 if (rc != EOK) {
397 printf(" Failed putting inode ref\n");
398 }
399}
400
401void print_inode(ext2_filesystem_t *fs, ext2_inode_t *inode, bool blocks)
402{
403 uint32_t mode;
404 uint32_t mode_type;
405 uint32_t user_id;
406 uint32_t group_id;
407 uint64_t size;
408 uint16_t usage_count;
409 uint32_t flags;
410 uint16_t access;
411 const char *type;
412 uint32_t total_blocks;
413 uint32_t i;
414 uint32_t range_start;
415 uint32_t range_last;
416 uint32_t range_start_file;
417 uint32_t range_last_file;
418 uint32_t range_current;
419 uint32_t range_expected;
420 uint32_t block_size;
421 uint64_t file_blocks;
422 bool printed_range;
423 int rc;
424
425 block_size = ext2_superblock_get_block_size(fs->superblock);
426 mode = ext2_inode_get_mode(fs->superblock, inode);
427 mode_type = mode & EXT2_INODE_MODE_TYPE_MASK;
428 user_id = ext2_inode_get_user_id(fs->superblock, inode);
429 group_id = ext2_inode_get_group_id(fs->superblock, inode);
430 size = ext2_inode_get_size(fs->superblock, inode);
431 usage_count = ext2_inode_get_usage_count(inode);
432 flags = ext2_inode_get_flags(inode);
433 total_blocks = ext2_inode_get_reserved_blocks(fs->superblock, inode);
434 file_blocks = 0;
435 if (size > 0) {
436 file_blocks = ((size-1)/block_size)+1;
437 }
438
439 type = "Unknown";
440 if (mode_type == EXT2_INODE_MODE_BLOCKDEV) {
441 type = "Block device";
442 }
443 else if (mode_type == EXT2_INODE_MODE_FIFO) {
444 type = "Fifo (pipe)";
445 }
446 else if (mode_type == EXT2_INODE_MODE_CHARDEV) {
447 type = "Character device";
448 }
449 else if (mode_type == EXT2_INODE_MODE_DIRECTORY) {
450 type = "Directory";
451 }
452 else if (mode_type == EXT2_INODE_MODE_FILE) {
453 type = "File";
454 }
455 else if (mode_type == EXT2_INODE_MODE_SOFTLINK) {
456 type = "Soft link";
457 }
458 else if (mode_type == EXT2_INODE_MODE_SOCKET) {
459 type = "Socket";
460 }
461
462 access = mode & EXT2_INODE_MODE_ACCESS_MASK;
463
464
465 printf(" Mode: %08x (Type: %s, Access bits: %04ho)\n", mode, type, access);
466 printf(" User ID: %u\n", user_id);
467 printf(" Group ID: %u\n", group_id);
468 printf(" Size: %" PRIu64 "\n", size);
469 printf(" Usage (link) count: %u\n", usage_count);
470 printf(" Flags: %u\n", flags);
471 printf(" Total allocated blocks: %u\n", total_blocks);
472
473 if (blocks) {
474 printf(" Block list: ");
475
476 range_start = 0;
477 range_current = 0;
478 range_last = 0;
479
480 printed_range = false;
481
482 for (i = 0; i <= file_blocks; i++) {
483 if (i < file_blocks) {
484 rc = ext2_filesystem_get_inode_data_block_index(fs, inode, i, &range_current);
485 if (rc != EOK) {
486 printf("Error reading data block indexes\n");
487 return;
488 }
489 }
490 if (range_last == 0) {
491 range_expected = 0;
492 }
493 else {
494 range_expected = range_last + 1;
495 }
496 if (range_current != range_expected) {
497 if (i > 0) {
498 if (printed_range) {
499 printf(", ");
500 }
501 if (range_start == 0 && range_last == 0) {
502 if (range_start_file == range_last_file) {
503 printf("%u N/A", range_start_file);
504 }
505 else {
506 printf("[%u, %u] N/A", range_start_file,
507 range_last_file);
508 }
509 }
510 else {
511 if (range_start_file == range_last_file) {
512 printf("%u -> %u", range_start_file, range_start);
513 }
514 else {
515 printf("[%u, %u] -> [%u, %u]", range_start_file,
516 range_last_file, range_start, range_last);
517 }
518 }
519 printed_range = true;
520 }
521 range_start = range_current;
522 range_start_file = i;
523 }
524 range_last = range_current;
525 range_last_file = i;
526 }
527 printf("\n");
528 }
529}
530
531void print_data(unsigned char *data, size_t size)
532{
533 unsigned char c;
534 size_t i;
535
536 for (i = 0; i < size; i++) {
537 c = data[i];
538 if (c >= 32 && c < 127) {
539 putchar(c);
540 }
541 else {
542 putchar('.');
543 }
544 }
545}
546
547void print_inode_data(ext2_filesystem_t *fs, ext2_inode_t *inode, uint32_t data)
548{
549 int rc;
550 uint32_t data_block_index;
551 block_t *block;
552
553 rc = ext2_filesystem_get_inode_data_block_index(fs, inode, data,
554 &data_block_index);
555
556 if (rc != EOK) {
557 printf("Failed getting data block #%u\n", data);
558 return;
559 }
560
561 printf("Data for inode contents block #%u is located in filesystem "
562 "block %u\n", data, data_block_index);
563
564 printf("Data preview (only printable characters):\n");
565
566 rc = block_get(&block, fs->device, data_block_index, 0);
567 if (rc != EOK) {
568 printf("Failed reading filesystem block %u\n", data_block_index);
569 return;
570 }
571
572 print_data(block->data, block->size);
573 printf("\n");
574
575 rc = block_put(block);
576 if (rc != EOK) {
577 printf("Failed putting filesystem block\n");
578 }
579
580}
581
582void print_directory_contents(ext2_filesystem_t *fs,
583 ext2_inode_ref_t *inode_ref)
584{
585 int rc;
586 ext2_directory_iterator_t it;
587 size_t name_size;
588
589 printf(" Directory contents:\n");
590
591 rc = ext2_directory_iterator_init(&it, fs, inode_ref);
592 if (rc != EOK) {
593 printf("Failed initializing directory iterator\n");
594 return;
595 }
596
597 while (it.current != NULL) {
598 name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
599 it.current);
600 printf(" ");
601 print_data(&it.current->name, name_size);
602 printf(" --> %u\n", it.current->inode);
603
604 rc = ext2_directory_iterator_next(&it);
605 if (rc != EOK) {
606 printf("Failed reading directory contents\n");
607 goto cleanup;
608 }
609 }
610
611cleanup:
612 rc = ext2_directory_iterator_fini(&it);
613 if (rc != EOK) {
614 printf("Failed cleaning-up directory iterator\n");
615 }
616
617}
618
619/**
620 * @}
621 */
Note: See TracBrowser for help on using the repository browser.