dumpe2fs.c revision d0ff90d5202428583c78a60c3042e7b60d88bc45
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 has_super;
138
139	if (fs->block_map)
140		block_bitmap = fs->block_map->bitmap;
141	if (fs->inode_map)
142		inode_bitmap = fs->inode_map->bitmap;
143
144	inode_blocks_per_group = ((fs->super->s_inodes_per_group *
145				   EXT2_INODE_SIZE(fs->super)) +
146				  EXT2_BLOCK_SIZE(fs->super) - 1) /
147				 EXT2_BLOCK_SIZE(fs->super);
148	reserved_gdt = fs->super->s_reserved_gdt_blocks;
149	fputc('\n', stdout);
150	first_block = fs->super->s_first_data_block;
151	if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
152		old_desc_blocks = fs->super->s_first_meta_bg;
153	else
154		old_desc_blocks = fs->desc_blocks;
155	for (i = 0; i < fs->group_desc_count; i++) {
156		ext2fs_super_and_bgd_loc(fs, i, &super_blk,
157					 &old_desc_blk, &new_desc_blk, 0);
158		if (i == fs->group_desc_count - 1)
159			last_block = fs->super->s_blocks_count - 1;
160		else
161			last_block = first_block +
162				     fs->super->s_blocks_per_group - 1;
163
164		printf (_("Group %lu: (Blocks "), i);
165		print_range(first_block, last_block);
166		fputs(")", stdout);
167		print_bg_opts(fs, i);
168		has_super = ((i==0) || super_blk);
169		if (has_super) {
170			printf (_("  %s superblock at "),
171				i == 0 ? _("Primary") : _("Backup"));
172			print_number(super_blk);
173		}
174		if (old_desc_blk) {
175			printf(_(", Group descriptors at "));
176			print_range(old_desc_blk,
177				    old_desc_blk + old_desc_blocks - 1);
178			if (reserved_gdt) {
179				printf(_("\n  Reserved GDT blocks at "));
180				print_range(old_desc_blk + old_desc_blocks,
181					    old_desc_blk + old_desc_blocks +
182					    reserved_gdt - 1);
183			}
184		} else if (new_desc_blk) {
185			fputc(has_super ? ',' : ' ', stdout);
186			printf(_(" Group descriptor at "));
187			print_number(new_desc_blk);
188			has_super++;
189		}
190		if (has_super)
191			fputc('\n', stdout);
192		fputs(_("  Block bitmap at "), stdout);
193		print_number(fs->group_desc[i].bg_block_bitmap);
194		diff = fs->group_desc[i].bg_block_bitmap - first_block;
195		if (diff >= 0)
196			printf(" (+%ld)", diff);
197		fputs(_(", Inode bitmap at "), stdout);
198		print_number(fs->group_desc[i].bg_inode_bitmap);
199		diff = fs->group_desc[i].bg_inode_bitmap - first_block;
200		if (diff >= 0)
201			printf(" (+%ld)", diff);
202		fputs(_("\n  Inode table at "), stdout);
203		print_range(fs->group_desc[i].bg_inode_table,
204			    fs->group_desc[i].bg_inode_table +
205			    inode_blocks_per_group - 1);
206		diff = fs->group_desc[i].bg_inode_table - first_block;
207		if (diff > 0)
208			printf(" (+%ld)", diff);
209		printf (_("\n  %d free blocks, %d free inodes, "
210			  "%d directories\n"),
211			fs->group_desc[i].bg_free_blocks_count,
212			fs->group_desc[i].bg_free_inodes_count,
213			fs->group_desc[i].bg_used_dirs_count);
214		if (block_bitmap) {
215			fputs(_("  Free blocks: "), stdout);
216			print_free (i, block_bitmap,
217				    fs->super->s_blocks_per_group,
218				    fs->super->s_first_data_block);
219			fputc('\n', stdout);
220			block_bitmap += fs->super->s_blocks_per_group / 8;
221		}
222		if (inode_bitmap) {
223			fputs(_("  Free inodes: "), stdout);
224			print_free (i, inode_bitmap,
225				    fs->super->s_inodes_per_group, 1);
226			fputc('\n', stdout);
227			inode_bitmap += fs->super->s_inodes_per_group / 8;
228		}
229		first_block += fs->super->s_blocks_per_group;
230	}
231}
232
233static void list_bad_blocks(ext2_filsys fs, int dump)
234{
235	badblocks_list		bb_list = 0;
236	badblocks_iterate	bb_iter;
237	blk_t			blk;
238	errcode_t		retval;
239	const char		*header, *fmt;
240
241	retval = ext2fs_read_bb_inode(fs, &bb_list);
242	if (retval) {
243		com_err("ext2fs_read_bb_inode", retval, 0);
244		return;
245	}
246	retval = ext2fs_badblocks_list_iterate_begin(bb_list, &bb_iter);
247	if (retval) {
248		com_err("ext2fs_badblocks_list_iterate_begin", retval,
249			_("while printing bad block list"));
250		return;
251	}
252	if (dump) {
253		header = fmt = "%u\n";
254	} else {
255		header =  _("Bad blocks: %u");
256		fmt = ", %u";
257	}
258	while (ext2fs_badblocks_list_iterate(bb_iter, &blk)) {
259		printf(header ? header : fmt, blk);
260		header = 0;
261	}
262	ext2fs_badblocks_list_iterate_end(bb_iter);
263	if (!dump)
264		fputc('\n', stdout);
265}
266
267static void print_inline_journal_information(ext2_filsys fs)
268{
269	struct ext2_inode	inode;
270	errcode_t		retval;
271	ino_t			ino = fs->super->s_journal_inum;
272	int			size;
273
274	retval = ext2fs_read_inode(fs, ino,  &inode);
275	if (retval) {
276		com_err(program_name, retval,
277			_("while reading journal inode"));
278		exit(1);
279	}
280	fputs(_("Journal size:             "), stdout);
281	size = inode.i_blocks >> 1;
282	if (size < 8192)
283		printf("%uk\n", size);
284	else
285		printf("%uM\n", size >> 10);
286}
287
288static void print_journal_information(ext2_filsys fs)
289{
290	errcode_t	retval;
291	char		buf[1024];
292	char		str[80];
293	unsigned int	i;
294	journal_superblock_t	*jsb;
295
296	/* Get the journal superblock */
297	if ((retval = io_channel_read_blk(fs->io, fs->super->s_first_data_block+1, -1024, buf))) {
298		com_err(program_name, retval,
299			_("while reading journal superblock"));
300		exit(1);
301	}
302	jsb = (journal_superblock_t *) buf;
303	if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
304	    (jsb->s_header.h_blocktype !=
305	     (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
306		com_err(program_name, 0,
307			_("Couldn't find journal superblock magic numbers"));
308		exit(1);
309	}
310
311	printf(_("\nJournal block size:       %u\n"
312		 "Journal length:           %u\n"
313		 "Journal first block:      %u\n"
314		 "Journal sequence:         0x%08x\n"
315		 "Journal start:            %u\n"
316		 "Journal number of users:  %u\n"),
317	       (unsigned int)ntohl(jsb->s_blocksize),  (unsigned int)ntohl(jsb->s_maxlen),
318	       (unsigned int)ntohl(jsb->s_first), (unsigned int)ntohl(jsb->s_sequence),
319	       (unsigned int)ntohl(jsb->s_start), (unsigned int)ntohl(jsb->s_nr_users));
320
321	for (i=0; i < ntohl(jsb->s_nr_users); i++) {
322		uuid_unparse(&jsb->s_users[i*16], str);
323		printf(i ? "                          %s\n"
324		       : _("Journal users:            %s\n"),
325		       str);
326	}
327}
328
329int main (int argc, char ** argv)
330{
331	errcode_t	retval;
332	ext2_filsys	fs;
333	int		print_badblocks = 0;
334	int		use_superblock = 0;
335	int		use_blocksize = 0;
336	int		image_dump = 0;
337	int		force = 0;
338	int		flags;
339	int		header_only = 0;
340	int		big_endian;
341	int		c;
342
343#ifdef ENABLE_NLS
344	setlocale(LC_MESSAGES, "");
345	setlocale(LC_CTYPE, "");
346	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
347	textdomain(NLS_CAT_NAME);
348#endif
349	initialize_ext2_error_table();
350	fprintf (stderr, "dumpe2fs %s (%s)\n", E2FSPROGS_VERSION,
351		 E2FSPROGS_DATE);
352	if (argc && *argv)
353		program_name = *argv;
354
355	while ((c = getopt (argc, argv, "bfhixVo:")) != EOF) {
356		switch (c) {
357		case 'b':
358			print_badblocks++;
359			break;
360		case 'f':
361			force++;
362			break;
363		case 'h':
364			header_only++;
365			break;
366		case 'i':
367			image_dump++;
368			break;
369		case 'o':
370			if (optarg[0] == 'b')
371				use_superblock = atoi(optarg+1);
372			else if (optarg[0] == 'B')
373				use_blocksize = atoi(optarg+1);
374			else
375				usage();
376			break;
377		case 'V':
378			/* Print version number and exit */
379			fprintf(stderr, _("\tUsing %s\n"),
380				error_message(EXT2_ET_BASE));
381			exit(0);
382		case 'x':
383			hex_format++;
384			break;
385		default:
386			usage();
387		}
388	}
389	if (optind > argc - 1)
390		usage();
391	device_name = argv[optind++];
392	if (use_superblock && !use_blocksize)
393		use_blocksize = 1024;
394	flags = EXT2_FLAG_JOURNAL_DEV_OK;
395	if (force)
396		flags |= EXT2_FLAG_FORCE;
397	if (image_dump)
398		flags |= EXT2_FLAG_IMAGE_FILE;
399
400	retval = ext2fs_open (device_name, flags, use_superblock,
401			      use_blocksize, unix_io_manager, &fs);
402	if (retval) {
403		com_err (program_name, retval, _("while trying to open %s"),
404			 device_name);
405		printf (_("Couldn't find valid filesystem superblock.\n"));
406		exit (1);
407	}
408	if (print_badblocks) {
409		list_bad_blocks(fs, 1);
410	} else {
411		big_endian = ((fs->flags & EXT2_FLAG_SWAP_BYTES) != 0);
412#ifdef WORDS_BIGENDIAN
413		big_endian = !big_endian;
414#endif
415		if (big_endian)
416			printf(_("Note: This is a byte-swapped filesystem\n"));
417		list_super (fs->super);
418		if (fs->super->s_feature_incompat &
419		      EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
420			print_journal_information(fs);
421			ext2fs_close(fs);
422			exit(0);
423		}
424		if (fs->super->s_feature_compat &
425		      EXT3_FEATURE_COMPAT_HAS_JOURNAL)
426			print_inline_journal_information(fs);
427		list_bad_blocks(fs, 0);
428		if (header_only) {
429			ext2fs_close (fs);
430			exit (0);
431		}
432		retval = ext2fs_read_bitmaps (fs);
433		list_desc (fs);
434		if (retval) {
435			printf(_("\n%s: %s: error reading bitmaps: %s\n"),
436			       program_name, device_name,
437			       error_message(retval));
438		}
439	}
440	ext2fs_close (fs);
441	exit (0);
442}
443