]>
Commit | Line | Data |
---|---|---|
74a74d22 TT |
1 | /* |
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. | |
efc6f628 | 9 | * |
74a74d22 | 10 | * Well, here's my linux version of findsuper. |
7f88b043 TT |
11 | * I'm sure you coulda done it faster. :) |
12 | * IMHO there isn't as much interesting data to print in the | |
13 | * linux superblock as there is in the SunOS superblock--disk geometry is | |
14 | * not there...and linux seems to update the dates in all the superblocks. | |
15 | * SunOS doesn't ever touch the backup superblocks after the fs is created, | |
16 | * as far as I can tell, so the date is more interesting IMHO and certainly | |
17 | * marks which superblocks are backup ones. | |
18 | * | |
7f88b043 TT |
19 | * I wanted to add msdos support, but I couldn't make heads or tails |
20 | * of the kernel include files to find anything I could look for in msdos. | |
efc6f628 | 21 | * |
7f88b043 TT |
22 | * Reading every block of a Sun partition is fairly quick. Doing the |
23 | * same under linux (slower hardware I suppose) just isn't the same. | |
24 | * It might be more useful to default to reading the first (second?) block | |
25 | * on each cyl; however, if the disk geometry is wrong, this is useless. | |
26 | * But ya could still get the cyl size to print the numbers as cyls instead | |
27 | * of blocks... | |
28 | * | |
29 | * run this as (for example) | |
30 | * findsuper /dev/hda | |
31 | * findsuper /dev/hda 437760 1024 (my disk has cyls of 855*512) | |
32 | * | |
055866d8 | 33 | * I suppose the next step is to figure out a way to determine if |
7f88b043 TT |
34 | * the block found is the first superblock somehow, and if so, build |
35 | * a partition table from the superblocks found... but this is still | |
36 | * useful as is. | |
37 | * | |
38 | * Steve | |
39 | * ssd@nevets.oau.org | |
40 | * ssd@mae.engr.ucf.edu | |
d6903ecc AD |
41 | * |
42 | * Additional notes by Andreas Dilger <adilger@turbolinux.com>: | |
43 | * - fixed to support > 2G devices by using lseek64 | |
44 | * - add reliability checking for the superblock to avoid random garbage | |
45 | * - add adaptive progress meter | |
46 | * | |
47 | * It _should_ also handle signals and tell you the ending block, so | |
48 | * that you can resume at a later time, but it doesn't yet... | |
49 | * | |
50 | * Note that gpart does not appear to find all superblocks that aren't aligned | |
51 | * with the start of a possible partition, so it is not useful in systems | |
52 | * with LVM or similar setups which don't use fat partition alignment. | |
16fa86b9 TT |
53 | * |
54 | * %Begin-Header% | |
55 | * This file may be redistributed under the terms of the GNU Public | |
56 | * License. | |
57 | * %End-Header% | |
7f88b043 TT |
58 | */ |
59 | ||
e2423cc0 TT |
60 | /* |
61 | * Documentation addendum added by Andreas dwguest@win.tue.nl/aeb@cwi.nl | |
efc6f628 | 62 | * |
e2423cc0 | 63 | * The program findsuper is a utility that scans a disk and finds |
bb145b01 | 64 | * copies of ext2 superblocks (by checking for the ext2 signature). |
efc6f628 | 65 | * |
e2423cc0 | 66 | * For each superblock found, it prints the offset in bytes, the |
bb145b01 | 67 | * offset in 1024-byte blocks, the size of the ext2 partition in fs |
d6903ecc AD |
68 | * blocks, the filesystem blocksize (in bytes), the block group number |
69 | * (always 0 for older ext2 systems), and a timestamp (s_mtime). | |
efc6f628 | 70 | * |
e2423cc0 TT |
71 | * This program can be used to retrieve partitions that have been |
72 | * lost. The superblock for block group 0 is found 1 block (2 | |
73 | * sectors) after the partition start. | |
efc6f628 | 74 | * |
e2423cc0 TT |
75 | * For new systems that have a block group number in the superblock it |
76 | * is immediately clear which superblock is the first of a partition. | |
77 | * For old systems where no group numbers are given, the first | |
055866d8 | 78 | * superblock can be recognized by the timestamp: all superblock |
e2423cc0 TT |
79 | * copies have the creation time in s_mtime, except the first, which |
80 | * has the last time e2fsck or tune2fs wrote to the filesystem. | |
efc6f628 | 81 | * |
e2423cc0 TT |
82 | */ |
83 | ||
d6903ecc | 84 | #define _FILE_OFFSET_BITS 64 |
e2423cc0 | 85 | |
d1154eb4 | 86 | #include "config.h" |
7f88b043 TT |
87 | #include <stdio.h> |
88 | #include <stdlib.h> | |
d6903ecc AD |
89 | #include <string.h> |
90 | #include <unistd.h> | |
91 | #include <errno.h> | |
92 | #include <fcntl.h> | |
7f88b043 TT |
93 | #include <time.h> |
94 | ||
54c637d4 | 95 | #include "ext2fs/ext2_fs.h" |
4efbac6f | 96 | #include "ext2fs/ext2fs.h" |
99ceb8ec | 97 | #include "support/nls-enable.h" |
7f88b043 | 98 | |
d6903ecc AD |
99 | #undef DEBUG |
100 | ||
101 | #ifdef DEBUG | |
102 | #define WHY(fmt, arg...) { printf("\r%Ld: " fmt, sk, ##arg) ; continue; } | |
103 | #else | |
104 | #define WHY(fmt, arg...) { continue; } | |
105 | #endif | |
7f88b043 | 106 | |
efc6f628 | 107 | static void usage(void) |
42fef8df | 108 | { |
efc6f628 | 109 | fprintf(stderr, |
42fef8df AD |
110 | _("Usage: findsuper device [skipbytes [startkb]]\n")); |
111 | exit(1); | |
112 | } | |
113 | ||
114 | ||
d6903ecc | 115 | int main(int argc, char *argv[]) |
7f88b043 | 116 | { |
19c78dc0 | 117 | int skiprate=512; /* one sector */ |
d6903ecc AD |
118 | loff_t sk=0, skl=0; |
119 | int fd; | |
19c78dc0 | 120 | char *s; |
d6903ecc AD |
121 | time_t tm, last = time(0); |
122 | loff_t interval = 1024 * 1024; | |
42fef8df AD |
123 | int c, print_jnl_copies = 0; |
124 | const char * device_name; | |
19c78dc0 TT |
125 | struct ext2_super_block ext2; |
126 | /* interesting fields: EXT2_SUPER_MAGIC | |
127 | * s_blocks_count s_log_block_size s_mtime s_magic s_lastcheck */ | |
d9c56d3c TT |
128 | |
129 | #ifdef ENABLE_NLS | |
130 | setlocale(LC_MESSAGES, ""); | |
14308a53 | 131 | setlocale(LC_CTYPE, ""); |
d9c56d3c TT |
132 | bindtextdomain(NLS_CAT_NAME, LOCALEDIR); |
133 | textdomain(NLS_CAT_NAME); | |
9d4507c5 | 134 | set_com_err_gettext(gettext); |
d9c56d3c | 135 | #endif |
42fef8df AD |
136 | |
137 | while ((c = getopt (argc, argv, "j")) != EOF) { | |
138 | switch (c) { | |
139 | case 'j': | |
140 | print_jnl_copies++; | |
141 | break; | |
142 | default: | |
143 | usage(); | |
144 | } | |
19c78dc0 | 145 | } |
42fef8df AD |
146 | |
147 | if (optind == argc) | |
148 | usage(); | |
149 | ||
150 | device_name = argv[optind++]; | |
151 | ||
152 | if (optind < argc) { | |
153 | skiprate = strtol(argv[optind], &s, 0); | |
154 | if (s == argv[optind]) { | |
155 | fprintf(stderr,_("skipbytes should be a number, not %s\n"), s); | |
156 | exit(1); | |
157 | } | |
158 | optind++; | |
d6903ecc AD |
159 | } |
160 | if (skiprate & 0x1ff) { | |
19c78dc0 | 161 | fprintf(stderr, |
d6903ecc | 162 | _("skipbytes must be a multiple of the sector size\n")); |
19c78dc0 TT |
163 | exit(2); |
164 | } | |
42fef8df AD |
165 | if (optind < argc) { |
166 | sk = skl = strtoll(argv[optind], &s, 0) << 10; | |
167 | if (s == argv[optind]) { | |
168 | fprintf(stderr, | |
169 | _("startkb should be a number, not %s\n"), s); | |
170 | exit(1); | |
171 | } | |
172 | optind++; | |
d6903ecc AD |
173 | } |
174 | if (sk < 0) { | |
3a941bef | 175 | fprintf(stderr, _("startkb should be positive, not %llu\n"),sk); |
19c78dc0 TT |
176 | exit(1); |
177 | } | |
efc6f628 | 178 | |
42fef8df | 179 | fd = open(device_name, O_RDONLY); |
d6903ecc | 180 | if (fd < 0) { |
42fef8df | 181 | perror(device_name); |
19c78dc0 TT |
182 | exit(1); |
183 | } | |
42fef8df | 184 | |
598ff014 | 185 | /* Now, go looking for the superblock! */ |
3a941bef | 186 | printf(_("starting at %llu, with %u byte increments\n"), sk, skiprate); |
42fef8df AD |
187 | if (print_jnl_copies) |
188 | printf(_("[*] probably superblock written in the ext3 " | |
189 | "journal superblock,\n\tso start/end/grp wrong\n")); | |
ba60bb90 | 190 | printf(_("byte_offset byte_start byte_end fs_blocks blksz grp mkfs/mount_time sb_uuid label\n")); |
d6903ecc AD |
191 | for (; lseek64(fd, sk, SEEK_SET) != -1 && |
192 | read(fd, &ext2, 512) == 512; sk += skiprate) { | |
42fef8df AD |
193 | static unsigned char last_uuid[16] = "blah"; |
194 | unsigned long long bsize, grpsize; | |
195 | int jnl_copy, sb_offset; | |
d6903ecc AD |
196 | |
197 | if (sk && !(sk & (interval - 1))) { | |
198 | time_t now, diff; | |
199 | ||
200 | now = time(0); | |
201 | diff = now - last; | |
202 | ||
203 | if (diff > 0) { | |
204 | s = ctime(&now); | |
205 | s[24] = 0; | |
42fef8df | 206 | printf("\r%11Lu: %8LukB/s @ %s", sk, |
d6903ecc AD |
207 | (((sk - skl)) / diff) >> 10, s); |
208 | fflush(stdout); | |
209 | } | |
210 | if (diff < 5) | |
211 | interval <<= 1; | |
212 | else if (diff > 20) | |
213 | interval >>= 1; | |
214 | last = now; | |
215 | skl = sk; | |
19c78dc0 | 216 | } |
e2423cc0 TT |
217 | if (ext2.s_magic != EXT2_SUPER_MAGIC) |
218 | continue; | |
42fef8df AD |
219 | if (ext2.s_log_block_size > 6) |
220 | WHY("log block size > 6 (%u)\n", ext2.s_log_block_size); | |
4efbac6f | 221 | if (ext2fs_r_blocks_count(&ext2) > ext2fs_blocks_count(&ext2)) |
8deb80a5 | 222 | WHY("r_blocks_count > blocks_count (%u > %u)\n", |
4efbac6f VAH |
223 | ext2fs_r_blocks_count(&ext2), |
224 | ext2fs_blocks_count(&ext2)); | |
225 | if (ext2fs_free_blocks_count(&ext2) > ext2fs_blocks_count(&ext2)) | |
8deb80a5 | 226 | WHY("free_blocks_count > blocks_count\n (%u > %u)\n", |
4efbac6f VAH |
227 | ext2fs_free_blocks_count(&ext2), |
228 | ext2fs_blocks_count(&ext2)); | |
d6903ecc | 229 | if (ext2.s_free_inodes_count > ext2.s_inodes_count) |
8deb80a5 | 230 | WHY("free_inodes_count > inodes_count (%u > %u)\n", |
d6903ecc AD |
231 | ext2.s_free_inodes_count, ext2.s_inodes_count); |
232 | ||
ba60bb90 AD |
233 | if (ext2.s_mkfs_time != 0) |
234 | tm = ext2.s_mkfs_time; | |
235 | else | |
236 | tm = ext2.s_mtime; | |
42fef8df AD |
237 | s = ctime(&tm); |
238 | s[24] = 0; | |
239 | bsize = 1 << (ext2.s_log_block_size + 10); | |
240 | grpsize = bsize * ext2.s_blocks_per_group; | |
241 | if (memcmp(ext2.s_uuid, last_uuid, sizeof(last_uuid)) == 0 && | |
242 | ext2.s_rev_level > 0 && ext2.s_block_group_nr == 0) { | |
243 | jnl_copy = 1; | |
244 | } else { | |
245 | jnl_copy = 0; | |
246 | memcpy(last_uuid, ext2.s_uuid, sizeof(last_uuid)); | |
247 | } | |
248 | if (ext2.s_block_group_nr == 0 || bsize == 1024) | |
249 | sb_offset = 1024; | |
250 | else | |
251 | sb_offset = 0; | |
252 | if (jnl_copy && !print_jnl_copies) | |
253 | continue; | |
254 | printf("\r%11Lu %11Lu%s %11Lu%s %9u %5Lu %4u%s %s %02x%02x%02x%02x %s\n", | |
255 | sk, sk - ext2.s_block_group_nr * grpsize - sb_offset, | |
256 | jnl_copy ? "*":" ", | |
4efbac6f | 257 | sk + ext2fs_blocks_count(&ext2) * bsize - |
42fef8df | 258 | ext2.s_block_group_nr * grpsize - sb_offset, |
4efbac6f | 259 | jnl_copy ? "*" : " ", ext2fs_blocks_count(&ext2), bsize, |
42fef8df AD |
260 | ext2.s_block_group_nr, jnl_copy ? "*" : " ", s, |
261 | ext2.s_uuid[0], ext2.s_uuid[1], | |
262 | ext2.s_uuid[2], ext2.s_uuid[3], ext2.s_volume_name); | |
19c78dc0 | 263 | } |
42fef8df | 264 | printf(_("\n%11Lu: finished with errno %d\n"), sk, errno); |
d6903ecc AD |
265 | close(fd); |
266 | ||
267 | return errno; | |
7f88b043 | 268 | } |