blob: 6eac4ee8040298cfc3e2e0b5f021c82f33327e9f [file] [log] [blame]
Theodore Ts'o74a74d22000-12-09 14:33:29 +00001/*
2 * findsuper --- quick hacked up program to find ext2 superblocks.
3 *
4 * This is a hack, and really shouldn't be installed anywhere. If you
5 * need a program which does this sort of functionality, please try
6 * using gpart program.
7 *
8 * Portions Copyright 1998-2000, Theodore Ts'o.
9 *
10 * This program may be used under the provisions of the GNU Public
Theodore Ts'o26900ae2000-12-09 21:46:59 +000011 * License, *EXCEPT* that a binary copy of the executable may not be
12 * packaged as a part of binary package which is distributed as part
13 * of a Linux distribution. (Yes, this violates the Debian Free
14 * Software Guidelines in terms of restricting its field of use.
15 * That's the point. I don't want this program being distributed in
16 * Debian, because I don't care to support it, and the maintainer,
17 * Yann Dirson, doesn't seem to pay attention to my wishes on this
18 * matter. So I'm delibiately adding this clause so it violates the
19 * Debian Free Software Guidelines to force him to take it out. If
20 * this doesn't work, I'll have to remove it from the upstream source
21 * distribution at the next release. End of Rant. :-)
22 *
Theodore Ts'o74a74d22000-12-09 14:33:29 +000023 *
24 * Well, here's my linux version of findsuper.
Theodore Ts'o7f88b041997-04-26 14:48:50 +000025 * I'm sure you coulda done it faster. :)
26 * IMHO there isn't as much interesting data to print in the
27 * linux superblock as there is in the SunOS superblock--disk geometry is
28 * not there...and linux seems to update the dates in all the superblocks.
29 * SunOS doesn't ever touch the backup superblocks after the fs is created,
30 * as far as I can tell, so the date is more interesting IMHO and certainly
31 * marks which superblocks are backup ones.
32 *
Theodore Ts'o7f88b041997-04-26 14:48:50 +000033 * I wanted to add msdos support, but I couldn't make heads or tails
34 * of the kernel include files to find anything I could look for in msdos.
35 *
36 * Reading every block of a Sun partition is fairly quick. Doing the
37 * same under linux (slower hardware I suppose) just isn't the same.
38 * It might be more useful to default to reading the first (second?) block
39 * on each cyl; however, if the disk geometry is wrong, this is useless.
40 * But ya could still get the cyl size to print the numbers as cyls instead
41 * of blocks...
42 *
43 * run this as (for example)
44 * findsuper /dev/hda
45 * findsuper /dev/hda 437760 1024 (my disk has cyls of 855*512)
46 *
47 * I suppose the next step is to figgure out a way to determine if
48 * the block found is the first superblock somehow, and if so, build
49 * a partition table from the superblocks found... but this is still
50 * useful as is.
51 *
52 * Steve
53 * ssd@nevets.oau.org
54 * ssd@mae.engr.ucf.edu
Andreas Dilgerd6903ec2001-10-01 15:38:14 -060055 *
56 * Additional notes by Andreas Dilger <adilger@turbolinux.com>:
57 * - fixed to support > 2G devices by using lseek64
58 * - add reliability checking for the superblock to avoid random garbage
59 * - add adaptive progress meter
60 *
61 * It _should_ also handle signals and tell you the ending block, so
62 * that you can resume at a later time, but it doesn't yet...
63 *
64 * Note that gpart does not appear to find all superblocks that aren't aligned
65 * with the start of a possible partition, so it is not useful in systems
66 * with LVM or similar setups which don't use fat partition alignment.
Theodore Ts'o7f88b041997-04-26 14:48:50 +000067 */
68
Theodore Ts'oe2423cc1999-06-18 00:51:31 +000069/*
70 * Documentation addendum added by Andreas dwguest@win.tue.nl/aeb@cwi.nl
71 *
72 * The program findsuper is a utility that scans a disk and finds
Andreas Dilgerd6903ec2001-10-01 15:38:14 -060073 * copies of ext2 superblocks (by checking for the ext2 signature
Theodore Ts'oe2423cc1999-06-18 00:51:31 +000074 *
75 * For each superblock found, it prints the offset in bytes, the
Andreas Dilgerd6903ec2001-10-01 15:38:14 -060076 * offset in 1024-byte blocks, the size of ext2 partition in fs
77 * blocks, the filesystem blocksize (in bytes), the block group number
78 * (always 0 for older ext2 systems), and a timestamp (s_mtime).
Theodore Ts'oe2423cc1999-06-18 00:51:31 +000079 *
80 * This program can be used to retrieve partitions that have been
81 * lost. The superblock for block group 0 is found 1 block (2
82 * sectors) after the partition start.
83 *
84 * For new systems that have a block group number in the superblock it
85 * is immediately clear which superblock is the first of a partition.
86 * For old systems where no group numbers are given, the first
87 * superblock can be recognised by the timestamp: all superblock
88 * copies have the creation time in s_mtime, except the first, which
89 * has the last time e2fsck or tune2fs wrote to the filesystem.
90 *
91 */
92
Andreas Dilgerd6903ec2001-10-01 15:38:14 -060093#define _FILE_OFFSET_BITS 64
Theodore Ts'oe2423cc1999-06-18 00:51:31 +000094
Theodore Ts'o7f88b041997-04-26 14:48:50 +000095#include <stdio.h>
96#include <stdlib.h>
Andreas Dilgerd6903ec2001-10-01 15:38:14 -060097#include <string.h>
98#include <unistd.h>
99#include <errno.h>
100#include <fcntl.h>
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000101#include <time.h>
102
Theodore Ts'o54c637d2001-05-14 11:45:38 +0000103#include "ext2fs/ext2_fs.h"
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000104#include "nls-enable.h"
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000105
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600106#undef DEBUG
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000107
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600108#ifdef DEBUG
109#define WHY(fmt, arg...) { printf("\r%Ld: " fmt, sk, ##arg) ; continue; }
110#else
111#define WHY(fmt, arg...) { continue; }
112#endif
113
114int main(int argc, char *argv[])
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000115{
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000116 int skiprate=512; /* one sector */
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600117 loff_t sk=0, skl=0;
118 int fd;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000119 char *s;
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600120 time_t tm, last = time(0);
121 loff_t interval = 1024 * 1024;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000122
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000123 struct ext2_super_block ext2;
124 /* interesting fields: EXT2_SUPER_MAGIC
125 * s_blocks_count s_log_block_size s_mtime s_magic s_lastcheck */
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000126
127#ifdef ENABLE_NLS
128 setlocale(LC_MESSAGES, "");
Theodore Ts'o14308a52002-03-05 03:26:52 -0500129 setlocale(LC_CTYPE, "");
Theodore Ts'od9c56d32000-02-08 00:47:55 +0000130 bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
131 textdomain(NLS_CAT_NAME);
132#endif
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000133 if (argc<2) {
134 fprintf(stderr,
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600135 _("Usage: findsuper device [skipbytes [startkb]]\n"));
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000136 exit(1);
137 }
138 if (argc>2)
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600139 skiprate = strtol(argv[2], &s, 0);
140 if (s == argv[2]) {
141 fprintf(stderr,_("skiprate should be a number, not %s\n"), s);
142 exit(1);
143 }
144 if (skiprate & 0x1ff) {
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000145 fprintf(stderr,
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600146 _("skipbytes must be a multiple of the sector size\n"));
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000147 exit(2);
148 }
149 if (argc>3)
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600150 sk = skl = strtoll(argv[3], &s, 0) << 10;
151 if (s == argv[3]) {
152 fprintf(stderr,_("startkb should be a number, not %s\n"), s);
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000153 exit(1);
154 }
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600155 if (sk < 0) {
156 fprintf(stderr,_("startkb should be positive, not %Ld\n"), sk);
157 exit(1);
158 }
159 fd = open(argv[1], O_RDONLY);
160 if (fd < 0) {
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000161 perror(argv[1]);
162 exit(1);
163 }
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000164
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000165 /* Now, go looking for the superblock ! */
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600166 printf(_("starting at %Ld, with %d byte increments\n"), sk, skiprate);
167 printf(_(" thisoff block fs_blk_sz blksz grp last_mount\n"));
168 for (; lseek64(fd, sk, SEEK_SET) != -1 &&
169 read(fd, &ext2, 512) == 512; sk += skiprate) {
170
171 if (sk && !(sk & (interval - 1))) {
172 time_t now, diff;
173
174 now = time(0);
175 diff = now - last;
176
177 if (diff > 0) {
178 s = ctime(&now);
179 s[24] = 0;
180 printf("\r%14Ld: %8LdkB/s @ %s", sk,
181 (((sk - skl)) / diff) >> 10, s);
182 fflush(stdout);
183 }
184 if (diff < 5)
185 interval <<= 1;
186 else if (diff > 20)
187 interval >>= 1;
188 last = now;
189 skl = sk;
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000190 }
Theodore Ts'oe2423cc1999-06-18 00:51:31 +0000191 if (ext2.s_magic != EXT2_SUPER_MAGIC)
192 continue;
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600193 if (ext2.s_log_block_size > 4)
194 WHY("log block size > 4 (%d)\n", ext2.s_log_block_size);
195 if (ext2.s_r_blocks_count > ext2.s_blocks_count)
196 WHY("r_blocks_count > blocks_count (%d > %d)\n",
197 ext2.s_r_blocks_count, ext2.s_blocks_count);
198 if (ext2.s_free_blocks_count > ext2.s_blocks_count)
199 WHY("free_blocks_count > blocks_count\n (%d > %d)\n",
200 ext2.s_free_blocks_count, ext2.s_blocks_count);
201 if (ext2.s_free_inodes_count > ext2.s_inodes_count)
202 WHY("free_inodes_count > inodes_count (%d > %d)\n",
203 ext2.s_free_inodes_count, ext2.s_inodes_count);
204
Theodore Ts'oe2423cc1999-06-18 00:51:31 +0000205 tm = ext2.s_mtime;
206 s=ctime(&tm);
207 s[24]=0;
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600208 printf("\r%14Ld %9Ld %9d %5d %4d %s\n",
209 sk, sk >> 10, ext2.s_blocks_count,
210 1 << (ext2.s_log_block_size + 10),
Theodore Ts'oe2423cc1999-06-18 00:51:31 +0000211 ext2.s_block_group_nr, s);
Theodore Ts'o19c78dc1997-04-29 16:17:09 +0000212 }
Andreas Dilgerd6903ec2001-10-01 15:38:14 -0600213 printf(_("\n%14Ld: finished with errno %d\n"), sk, errno);
214 close(fd);
215
216 return errno;
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000217}