dumpe2fs.c revision f1f115a78f5ea599fc5f8815a741d43fedd5840d
1/*
2 * dumpe2fs.c		- List the control structures of a second
3 *			  extended filesystem
4 *
5 * Copyright (C) 1992, 1993, 1994  Remy Card <card@masi.ibp.fr>
6 *                                 Laboratoire MASI, Institut Blaise Pascal
7 *                                 Universite Pierre et Marie Curie (Paris VI)
8 *
9 * Copyright 1995, 1996, 1997 by Theodore Ts'o.
10 *
11 * %Begin-Header%
12 * This file may be redistributed under the terms of the GNU Public
13 * License.
14 * %End-Header%
15 */
16
17/*
18 * History:
19 * 94/01/09	- Creation
20 * 94/02/27	- Ported to use the ext2fs library
21 */
22
23#ifdef HAVE_GETOPT_H
24#include <getopt.h>
25#else
26extern char *optarg;
27extern int optind;
28#endif
29#include <fcntl.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34
35#include "ext2fs/ext2_fs.h"
36
37#include "ext2fs/ext2fs.h"
38#include "e2p/e2p.h"
39#include "jfs_user.h"
40#include <uuid/uuid.h>
41
42#include "../version.h"
43#include "nls-enable.h"
44
45#define in_use(m, x)	(ext2fs_test_bit ((x), (m)))
46
47const char * program_name = "dumpe2fs";
48char * device_name = NULL;
49int hex_format = 0;
50
51static void usage(void)
52{
53	fprintf (stderr, _("Usage: %s [-bfhixV] [-ob superblock] "
54		 "[-oB blocksize] device\n"), program_name);
55	exit (1);
56}
57
58static void print_number(unsigned long num)
59{
60	if (hex_format)
61		printf("0x%04lx", num);
62	else
63		printf("%lu", num);
64}
65
66static void print_range(unsigned long a, unsigned long b)
67{
68	if (hex_format)
69		printf("0x%04lx-0x%04lx", a, b);
70	else
71		printf("%lu-%lu", a, b);
72}
73
74static void print_free (unsigned long group, char * bitmap,
75			unsigned long nbytes, unsigned long offset)
76{
77	int p = 0;
78	unsigned long i;
79	unsigned long j;
80
81	offset += group * nbytes;
82	for (i = 0; i < nbytes; i++)
83		if (!in_use (bitmap, i))
84		{
85			if (p)
86				printf (", ");
87			print_number(i + offset);
88			for (j = i; j < nbytes && !in_use (bitmap, j); j++)
89				;
90			if (--j != i) {
91				fputc('-', stdout);
92				print_number(j + offset);
93				i = j;
94			}
95			p = 1;
96		}
97}
98
99static void print_bg_opt(int bg_flags, int mask,
100			  const char *str, int *first)
101{
102	if (bg_flags & mask) {
103		if (*first) {
104			fputs(" [", stdout);
105			*first = 0;
106		} else
107			fputs(", ", stdout);
108		fputs(str, stdout);
109	}
110}
111static void print_bg_opts(ext2_filsys fs, dgrp_t i)
112{
113	int first = 1, bg_flags;
114
115	if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_LAZY_BG)
116		bg_flags = fs->group_desc[i].bg_flags;
117	else
118		bg_flags = 0;
119
120	print_bg_opt(bg_flags, EXT2_BG_INODE_UNINIT, "Inode not init",
121 		     &first);
122	print_bg_opt(bg_flags, EXT2_BG_BLOCK_UNINIT, "Block not init",
123 		     &first);
124	if (!first)
125		fputc(']', stdout);
126	fputc('\n', stdout);
127}
128
129static void list_desc (ext2_filsys fs)
130{
131	unsigned long i;
132	long diff;
133	blk_t	first_block, last_block;
134	blk_t	super_blk, old_desc_blk, new_desc_blk;
135	char *block_bitmap=NULL, *inode_bitmap=NULL;
136	int inode_blocks_per_group, old_desc_blocks, reserved_gdt;
137	int		block_nbytes, inode_nbytes;
138	int has_super;
139	blk_t		blk_itr = fs->super->s_first_data_block;
140	ext2_ino_t	ino_itr = 1;
141
142	block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
143	inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8;
144
145	if (fs->block_map)
146		block_bitmap = malloc(block_nbytes);
147	if (fs->inode_map)
148		inode_bitmap = malloc(inode_nbytes);
149
150	inode_blocks_per_group = ((fs->super->s_inodes_per_group *
151				   EXT2_INODE_SIZE(fs->super)) +
152				  EXT2_BLOCK_SIZE(fs->super) - 1) /
153				 EXT2_BLOCK_SIZE(fs->super);
154	reserved_gdt = fs->super->s_reserved_gdt_blocks;
155	fputc('\n', stdout);
156	first_block = fs->super->s_first_data_block;
157	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
158		old_desc_blocks = fs->super->s_first_meta_bg;
159	else
160		old_desc_blocks = fs->desc_blocks;
161	for (i = 0; i < fs->group_desc_count; i++) {
162		first_block = ext2fs_group_first_block(fs, i);
163		last_block = ext2fs_group_last_block(fs, i);
164
165		ext2fs_super_and_bgd_loc(fs, i, &super_blk,
166					 &old_desc_blk, &new_desc_blk, 0);
167
168		printf (_("Group %lu: (Blocks "), i);
169		print_range(first_block, last_block);
170		fputs(")", stdout);
171		print_bg_opts(fs, i);
172		has_super = ((i==0) || super_blk);
173		if (has_super) {
174			printf (_("  %s superblock at "),
175				i == 0 ? _("Primary") : _("Backup"));
176			print_number(super_blk);
177		}
178		if (old_desc_blk) {
179			printf(_(", Group descriptors at "));
180			print_range(old_desc_blk,
181				    old_desc_blk + old_desc_blocks - 1);
182			if (reserved_gdt) {
183				printf(_("\n  Reserved GDT blocks at "));
184				print_range(old_desc_blk + old_desc_blocks,
185					    old_desc_blk + old_desc_blocks +
186					    reserved_gdt - 1);
187			}
188		} else if (new_desc_blk) {
189			fputc(has_super ? ',' : ' ', stdout);
190			printf(_(" Group descriptor at "));
191			print_number(new_desc_blk);
192			has_super++;
193		}
194		if (has_super)
195			fputc('\n', stdout);
196		fputs(_("  Block bitmap at "), stdout);
197		print_number(fs->group_desc[i].bg_block_bitmap);
198		diff = fs->group_desc[i].bg_block_bitmap - first_block;
199		if (diff >= 0)
200			printf(" (+%ld)", diff);
201		fputs(_(", Inode bitmap at "), stdout);
202		print_number(fs->group_desc[i].bg_inode_bitmap);
203		diff = fs->group_desc[i].bg_inode_bitmap - first_block;
204		if (diff >= 0)
205			printf(" (+%ld)", diff);
206		fputs(_("\n  Inode table at "), stdout);
207		print_range(fs->group_desc[i].bg_inode_table,
208			    fs->group_desc[i].bg_inode_table +
209			    inode_blocks_per_group - 1);
210		diff = fs->group_desc[i].bg_inode_table - first_block;
211		if (diff > 0)
212			printf(" (+%ld)", diff);
213		printf (_("\n  %d free blocks, %d free inodes, "
214			  "%d directories\n"),
215			fs->group_desc[i].bg_free_blocks_count,
216			fs->group_desc[i].bg_free_inodes_count,
217			fs->group_desc[i].bg_used_dirs_count);
218		if (block_bitmap) {
219			fputs(_("  Free blocks: "), stdout);
220			ext2fs_get_block_bitmap_range(fs->block_map,
221				 blk_itr, block_nbytes << 3, block_bitmap);
222			print_free (i, block_bitmap,
223				    fs->super->s_blocks_per_group,
224				    fs->super->s_first_data_block);
225			fputc('\n', stdout);
226			blk_itr += fs->super->s_blocks_per_group;
227		}
228		if (inode_bitmap) {
229			fputs(_("  Free inodes: "), stdout);
230			ext2fs_get_inode_bitmap_range(fs->inode_map,
231				 ino_itr, inode_nbytes << 3, inode_bitmap);
232			print_free (i, inode_bitmap,
233				    fs->super->s_inodes_per_group, 1);
234			fputc('\n', stdout);
235			ino_itr += fs->super->s_inodes_per_group;
236		}
237	}
238}
239
240static void list_bad_blocks(ext2_filsys fs, int dump)
241{
242	badblocks_list		bb_list = 0;
243	badblocks_iterate	bb_iter;
244	blk_t			blk;
245	errcode_t		retval;
246	const char		*header, *fmt;
247
248	retval = ext2fs_read_bb_inode(fs, &bb_list);
249	if (retval) {
250		com_err("ext2fs_read_bb_inode", retval, 0);
251		return;
252	}
253	retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
254	if (retval) {
255		com_err("ext2fs_badblocks_list_iterate_begin", retval,
256			_("while printing bad block list"));
257		return;
258	}
259	if (dump) {
260		header = fmt = "%u\n";
261	} else {
262		header =  _("Bad blocks: %u");
263		fmt = ", %u";
264	}
265	while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
266		printf(header ? header : fmt, blk);
267		header = 0;
268	}
269	ext2fs_badblocks_list_iterate_end(bb_iter);
270	if (!dump)
271		fputc('\n', stdout);
272}
273
274static void print_inline_journal_information(ext2_filsys fs)
275{
276	struct ext2_inode	inode;
277	errcode_t		retval;
278	ino_t			ino = fs->super->s_journal_inum;
279	int			size;
280
281	retval = ext2fs_read_inode(fs, ino,  &inode);
282	if (retval) {
283		com_err(program_name, retval,
284			_("while reading journal inode"));
285		exit(1);
286	}
287	fputs(_("Journal size:             "), stdout);
288	size = inode.i_blocks >> 1;
289	if (size < 8192)
290		printf("%uk\n", size);
291	else
292		printf("%uM\n", size >> 10);
293}
294
295static void print_journal_information(ext2_filsys fs)
296{
297	errcode_t	retval;
298	char		buf[1024];
299	char		str[80];
300	unsigned int	i;
301	journal_superblock_t	*jsb;
302
303	/* Get the journal superblock */
304	if ((retval = io_channel_read_blk(fs->io, fs->super->s_first_data_block+1, -1024, buf))) {
305		com_err(program_name, retval,
306			_("while reading journal superblock"));
307		exit(1);
308	}
309	jsb = (journal_superblock_t *) buf;
310	if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
311	    (jsb->s_header.h_blocktype !=
312	     (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
313		com_err(program_name, 0,
314			_("Couldn't find journal superblock magic numbers"));
315		exit(1);
316	}
317
318	printf(_("\nJournal block size:       %u\n"
319		 "Journal length:           %u\n"
320		 "Journal first block:      %u\n"
321		 "Journal sequence:         0x%08x\n"
322		 "Journal start:            %u\n"
323		 "Journal number of users:  %u\n"),
324	       (unsigned int)ntohl(jsb->s_blocksize),  (unsigned int)ntohl(jsb->s_maxlen),
325	       (unsigned int)ntohl(jsb->s_first), (unsigned int)ntohl(jsb->s_sequence),
326	       (unsigned int)ntohl(jsb->s_start), (unsigned int)ntohl(jsb->s_nr_users));
327
328	for (i=0; i < ntohl(jsb->s_nr_users); i++) {
329		uuid_unparse(&jsb->s_users[i*16], str);
330		printf(i ? "                          %s\n"
331		       : _("Journal users:            %s\n"),
332		       str);
333	}
334}
335
336int main (int argc, char ** argv)
337{
338	errcode_t	retval;
339	ext2_filsys	fs;
340	int		print_badblocks = 0;
341	int		use_superblock = 0;
342	int		use_blocksize = 0;
343	int		image_dump = 0;
344	int		force = 0;
345	int		flags;
346	int		header_only = 0;
347	int		big_endian;
348	int		c;
349
350#ifdef ENABLE_NLS
351	setlocale(LC_MESSAGES, "");
352	setlocale(LC_CTYPE, "");
353	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
354	textdomain(NLS_CAT_NAME);
355#endif
356	add_error_table(&et_ext2_error_table);
357	fprintf (stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION,
358		 E2FSPROGS_DATE);
359	if (argc && *argv)
360		program_name = *argv;
361
362	while ((c = getopt (argc, argv, "bfhixVo:")) != EOF) {
363		switch (c) {
364		case 'b':
365			print_badblocks++;
366			break;
367		case 'f':
368			force++;
369			break;
370		case 'h':
371			header_only++;
372			break;
373		case 'i':
374			image_dump++;
375			break;
376		case 'o':
377			if (optarg[0] == 'b')
378				use_superblock = atoi(optarg+1);
379			else if (optarg[0] == 'B')
380				use_blocksize = atoi(optarg+1);
381			else
382				usage();
383			break;
384		case 'V':
385			/* Print version number and exit */
386			fprintf(stderr, _("\tUsing %s\n"),
387				error_message(EXT2_ET_BASE));
388			exit(0);
389		case 'x':
390			hex_format++;
391			break;
392		default:
393			usage();
394		}
395	}
396	if (optind > argc - 1)
397		usage();
398	device_name = argv[optind++];
399	if (use_superblock && !use_blocksize)
400		use_blocksize = 1024;
401	flags = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SOFTSUPP_FEATURES;
402	if (force)
403		flags |= EXT2_FLAG_FORCE;
404	if (image_dump)
405		flags |= EXT2_FLAG_IMAGE_FILE;
406
407	retval = ext2fs_open (device_name, flags, use_superblock,
408			      use_blocksize, unix_io_manager, &fs);
409	if (retval) {
410		com_err (program_name, retval, _("while trying to open %s"),
411			 device_name);
412		printf (_("Couldn't find valid filesystem superblock.\n"));
413		exit (1);
414	}
415	if (print_badblocks) {
416		list_bad_blocks(fs, 1);
417	} else {
418		big_endian = ((fs->flags & EXT2_FLAG_SWAP_BYTES) != 0);
419#ifdef WORDS_BIGENDIAN
420		big_endian = !big_endian;
421#endif
422		if (big_endian)
423			printf(_("Note: This is a byte-swapped filesystem\n"));
424		list_super (fs->super);
425		if (fs->super->s_feature_incompat &
426		      EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
427			print_journal_information(fs);
428			ext2fs_close(fs);
429			exit(0);
430		}
431		if (fs->super->s_feature_compat &
432		      EXT3_FEATURE_COMPAT_HAS_JOURNAL)
433			print_inline_journal_information(fs);
434		list_bad_blocks(fs, 0);
435		if (header_only) {
436			ext2fs_close (fs);
437			exit (0);
438		}
439		retval = ext2fs_read_bitmaps (fs);
440		list_desc (fs);
441		if (retval) {
442			printf(_("\n%s: %s: error reading bitmaps: %s\n"),
443			       program_name, device_name,
444			       error_message(retval));
445		}
446	}
447	ext2fs_close (fs);
448	remove_error_table(&et_ext2_error_table);
449	exit (0);
450}
451