e2freefrag.c revision 4efbac6fed75c29d3d5f1b676b932754653a2ac5
10b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o/*
20b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * e2freefrag - report filesystem free-space fragmentation
30b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o *
40b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * Copyright (C) 2009 Sun Microsystems, Inc.
50b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o *
60b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * Author: Rupesh Thakare <rupesh@sun.com>
70b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o *         Andreas Dilger <adilger@sun.com>
80b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o *
90b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * %Begin-Header%
100b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * This file may be redistributed under the terms of the GNU Public
110b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * License version 2.
120b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o * %End-Header%
130b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o */
140b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include <stdio.h>
150b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#ifdef HAVE_UNISTD_H
160b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include <unistd.h>
170b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#endif
180b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#ifdef HAVE_STDLIB_H
190b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include <stdlib.h>
200b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#endif
210b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#ifdef HAVE_GETOPT_H
220b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include <getopt.h>
230b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#else
240b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'oextern char *optarg;
250b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'oextern int optind;
260b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#endif
270b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
280b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include "ext2fs/ext2_fs.h"
290b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include "ext2fs/ext2fs.h"
300b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o#include "e2freefrag.h"
310b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
320b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'ovoid usage(const char *prog)
330b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
340b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	fprintf(stderr, "usage: %s [-c chunksize in kb] [-h] "
350b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		"device_name\n", prog);
360b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	exit(1);
370b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
380b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
390b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'ostatic int ul_log2(unsigned long arg)
400b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
410b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o        int     l = 0;
420b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
430b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o        arg >>= 1;
440b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o        while (arg) {
450b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o                l++;
460b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o                arg >>= 1;
470b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o        }
480b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o        return l;
490b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
500b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
510b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'ovoid init_chunk_info(ext2_filsys fs, struct chunk_info *info)
520b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
530b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	int i;
540b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
550b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	info->blocksize_bits = ul_log2((unsigned long)fs->blocksize);
56cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	if (info->chunkbytes) {
57cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		info->chunkbits = ul_log2(info->chunkbytes);
58cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		info->blks_in_chunk = info->chunkbytes >> info->blocksize_bits;
59cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	} else {
60cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		info->chunkbits = ul_log2(DEFAULT_CHUNKSIZE);
61cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		info->blks_in_chunk = DEFAULT_CHUNKSIZE >> info->blocksize_bits;
62cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	}
630b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
640b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	info->min = ~0UL;
650b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	info->max = info->avg = 0;
660b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	info->real_free_chunks = 0;
670b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
68ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger	for (i = 0; i < MAX_HIST; i++) {
69ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger		info->histogram.fc_chunks[i] = 0;
70ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger		info->histogram.fc_blocks[i] = 0;
71ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger	}
720b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
730b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
741e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'ovoid update_chunk_stats(struct chunk_info *info, unsigned long chunk_size)
751e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o{
761e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	unsigned long index;
771e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o
781e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	index = ul_log2(chunk_size) + 1;
791e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	if (index >= MAX_HIST)
801e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		index = MAX_HIST-1;
811e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	info->histogram.fc_chunks[index]++;
821e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	info->histogram.fc_blocks[index] += chunk_size;
831e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o
841e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	if (chunk_size > info->max)
851e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		info->max = chunk_size;
861e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	if (chunk_size < info->min)
871e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		info->min = chunk_size;
881e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	info->avg += chunk_size;
891e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	info->real_free_chunks++;
901e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o}
911e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o
920b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'ovoid scan_block_bitmap(ext2_filsys fs, struct chunk_info *info)
930b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
944efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson	unsigned long long blocks_count = ext2fs_blocks_count(fs->super);
950b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long long chunks = (blocks_count + info->blks_in_chunk) >>
960b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				(info->chunkbits - info->blocksize_bits);
970b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long long chunk_num;
980b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long last_chunk_size = 0;
990b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long long chunk_start_blk = 0;
1003e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o	int used;
1010b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1020b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	for (chunk_num = 0; chunk_num < chunks; chunk_num++) {
1030b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		unsigned long long blk, num_blks;
1040b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		int chunk_free;
1050b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1060b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		/* Last chunk may be smaller */
1070b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		if (chunk_start_blk + info->blks_in_chunk > blocks_count)
1080b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			num_blks = blocks_count - chunk_start_blk;
1090b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		else
1100b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			num_blks = info->blks_in_chunk;
1110b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1120b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		chunk_free = 0;
1130b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1140b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		/* Initialize starting block for first chunk correctly else
1150b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		 * there is a segfault when blocksize = 1024 in which case
1160b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		 * block_map->start = 1 */
1173e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o		for (blk = 0; blk < num_blks; blk++, chunk_start_blk++) {
1183e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o			if (chunk_num == 0 && blk == 0) {
1193e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o				blk = fs->super->s_first_data_block;
1203e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o				chunk_start_blk = blk;
1213e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o			}
1223c041a514cf65c65e102ff22e0dee2a3fa724873Valerie Aurora Henson			used = ext2fs_fast_test_block_bitmap2(fs->block_map,
1233e343b8d9af349301a2acd6b4328fb5663deb60cTheodore Ts'o							     chunk_start_blk);
1240b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			if (!used) {
1250b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				last_chunk_size++;
1260b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				chunk_free++;
1270b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			}
1280b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1290b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			if (used && last_chunk_size != 0) {
1301e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o				update_chunk_stats(info, last_chunk_size);
1310b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				last_chunk_size = 0;
1320b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			}
1330b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		}
1340b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1350b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		if (chunk_free == info->blks_in_chunk)
1360b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			info->free_chunks++;
1370b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
1381e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o	if (last_chunk_size != 0)
1391e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		update_chunk_stats(info, last_chunk_size);
1400b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
1410b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1420b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'oerrcode_t get_chunk_info(ext2_filsys fs, struct chunk_info *info)
1430b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
1440b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long total_chunks;
1450b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	char *unitp = "KMGTPEZY";
1460b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	int units = 10;
1470b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned long start = 0, end, cum;
1480b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	int i, retval = 0;
1490b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1500b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	scan_block_bitmap(fs, info);
1510b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1524efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson	printf("Total blocks: %llu\nFree blocks: %u (%0.1f%%)\n",
1534efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson	       ext2fs_blocks_count(fs->super), fs->super->s_free_blocks_count,
1540b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	       (double)fs->super->s_free_blocks_count * 100 /
1554efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson	       ext2fs_blocks_count(fs->super));
1560b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
157cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	if (info->chunkbytes) {
158cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		printf("\nChunksize: %lu bytes (%u blocks)\n",
159cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		       info->chunkbytes, info->blks_in_chunk);
1604efbac6fed75c29d3d5f1b676b932754653a2ac5Valerie Aurora Henson		total_chunks = (ext2fs_blocks_count(fs->super) +
161cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o				info->blks_in_chunk) >>
162cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o			(info->chunkbits - info->blocksize_bits);
163cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		printf("Total chunks: %lu\nFree chunks: %lu (%0.1f%%)\n",
164cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		       total_chunks, info->free_chunks,
165cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o		       (double)info->free_chunks * 100 / total_chunks);
166cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	}
1670b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
1680b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	/* Display chunk information in KB */
1690b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (info->real_free_chunks) {
1700b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		info->min = (info->min * fs->blocksize) >> 10;
1710b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		info->max = (info->max * fs->blocksize) >> 10;
1720b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		info->avg = (info->avg / info->real_free_chunks *
1730b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			     fs->blocksize) >> 10;
1740b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	} else {
1750b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		info->min = 0;
1760b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
1770b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
178aff2cf8ed2dfd5f453075122738ba6fdacda334eTheodore Ts'o	printf("\nMin. free extent: %lu KB \nMax. free extent: %lu KB\n"
179aff2cf8ed2dfd5f453075122738ba6fdacda334eTheodore Ts'o	       "Avg. free extent: %lu KB\n", info->min, info->max, info->avg);
1800b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
181aff2cf8ed2dfd5f453075122738ba6fdacda334eTheodore Ts'o	printf("\nHISTOGRAM OF FREE EXTENT SIZES:\n");
182aff2cf8ed2dfd5f453075122738ba6fdacda334eTheodore Ts'o	printf("%s :  %12s  %12s  %7s\n", "Extent Size Range", "Free extents",
183ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger	       "Free Blocks", "Percent");
1840b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	for (i = 0; i < MAX_HIST; i++) {
1850b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		end = 1 << (i + info->blocksize_bits - units);
1861e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		if (info->histogram.fc_chunks[i] != 0) {
1871e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o			char end_str[32];
1881e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o
1891e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o			sprintf(end_str, "%5lu%c-", end, *unitp);
1901e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o			if (i == MAX_HIST-1)
1911e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o				strcpy(end_str, "max ");
1921e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o			printf("%5lu%c...%7s  :  %12lu  %12lu  %6.2f%%\n",
1931e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o			       start, *unitp, end_str,
194ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger			       info->histogram.fc_chunks[i],
195ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger			       info->histogram.fc_blocks[i],
196ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger			       (double)info->histogram.fc_blocks[i] * 100 /
197ad751f11ecab50ec78a4b50ae95af3e7b2c4f06aAndreas Dilger			       fs->super->s_free_blocks_count);
1981e48a456b6ca646d66483761e959a81ae78b9156Theodore Ts'o		}
1990b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		start = end;
2000b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		if (start == 1<<10) {
2010b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			start = 1;
2020b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			units += 10;
2030b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			unitp++;
2040b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		}
2050b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
2060b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2070b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	return retval;
2080b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
2090b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2100b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'ovoid close_device(char *device_name, ext2_filsys fs)
2110b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
2120b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	int retval = ext2fs_close(fs);
2130b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2140b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (retval)
2150b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		com_err(device_name, retval, "while closing the filesystem.\n");
2160b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
2170b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2180b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'ovoid collect_info(ext2_filsys fs, struct chunk_info *chunk_info)
2190b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
2200b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	unsigned int retval = 0, i, free_blks;
2210b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2220b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	printf("Device: %s\n", fs->device_name);
2230b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	printf("Blocksize: %u bytes\n", fs->blocksize);
2240b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2250b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	retval = ext2fs_read_block_bitmap(fs);
2260b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (retval) {
2270b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		com_err(fs->device_name, retval, "while reading block bitmap");
2280b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		close_device(fs->device_name, fs);
2290b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		exit(1);
2300b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
2310b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2320b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	init_chunk_info(fs, chunk_info);
2330b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2340b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	retval = get_chunk_info(fs, chunk_info);
2350b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (retval) {
2360b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		com_err(fs->device_name, retval, "while collecting chunk info");
2370b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o                close_device(fs->device_name, fs);
2380b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		exit(1);
2390b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
2400b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
2410b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2420b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'ovoid open_device(char *device_name, ext2_filsys *fs)
2430b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
2440b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	int retval;
2450b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	int flag = EXT2_FLAG_FORCE;
2460b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2470b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	retval = ext2fs_open(device_name, flag, 0, 0, unix_io_manager, fs);
2480b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (retval) {
2490b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		com_err(device_name, retval, "while opening filesystem");
2500b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		exit(1);
2510b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
2520b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
2530b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2540b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'oint main(int argc, char *argv[])
2550b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o{
256cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	struct chunk_info chunk_info = { };
2570b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	errcode_t retval = 0;
2580b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	ext2_filsys fs = NULL;
2590b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	char *device_name;
2600b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	char *progname;
2610b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	char c, *end;
2620b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
263137a7dc05c80cd4e0a4e7aeb21ec79f800a9eecdTheodore Ts'o	add_error_table(&et_ext2_error_table);
2640b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	progname = argv[0];
2650b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2660b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	while ((c = getopt(argc, argv, "c:h")) != EOF) {
2670b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		switch (c) {
2680b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		case 'c':
2690b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			chunk_info.chunkbytes = strtoull(optarg, &end, 0);
2700b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			if (*end != '\0') {
2710b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				fprintf(stderr, "%s: bad chunk size '%s'\n",
2720b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o					progname, optarg);
2730b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				usage(progname);
2740b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			}
2750b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			if (chunk_info.chunkbytes &
2760b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			    (chunk_info.chunkbytes - 1)) {
2770b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				fprintf(stderr, "%s: chunk size must be a "
278aff2cf8ed2dfd5f453075122738ba6fdacda334eTheodore Ts'o					"power of 2.\n", argv[0]);
2790b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				usage(progname);
2800b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			}
2810b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			chunk_info.chunkbytes *= 1024;
2820b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			break;
2830b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		default:
2840b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			fprintf(stderr, "%s: bad option '%c'\n",
2850b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o				progname, c);
2860b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		case 'h':
2870b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			usage(progname);
2880b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			break;
2890b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		}
2900b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
2910b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2920b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	if (optind == argc) {
2930b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		fprintf(stderr, "%s: missing device name.\n", progname);
2940b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		usage(progname);
2950b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
2960b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2970b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	device_name = argv[optind];
2980b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
2990b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	open_device(device_name, &fs);
3000b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
301cba91c4b52f9e2fb3afee5513e87d95f9193421aTheodore Ts'o	if (chunk_info.chunkbytes && (chunk_info.chunkbytes < fs->blocksize)) {
3020b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		fprintf(stderr, "%s: chunksize must be greater than or equal "
3030b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o			"to filesystem blocksize.\n", progname);
3040b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o		exit(1);
3050b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	}
3060b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	collect_info(fs, &chunk_info);
3070b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	close_device(device_name, fs);
3080b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o
3090b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o	return retval;
3100b2681f45b7f67eedfea6411eddbb858699ae553Theodore Ts'o}
311