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