From: Rene Herman <rene.herman@gmail.com>
To: Theodore Tso <tytso@mit.edu>, Rene Herman <rene.herman@gmail.com>,
Al Boldi <a1426z@gawab.com>,
linux-raid@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [RFH] Partition table recovery
Date: Sun, 22 Jul 2007 11:11:49 +0200 [thread overview]
Message-ID: <46A31F55.2000009@gmail.com> (raw)
In-Reply-To: <20070722011141.GJ26752@thunk.org>
[-- Attachment #1: Type: text/plain, Size: 3936 bytes --]
On 07/22/2007 03:11 AM, Theodore Tso wrote:
>> This is a problem. Today the CHS fields in the partition entries don't
>> mean much of anything anymore and Linux happily ignores them but DOS
>> and (hence) Windows 9x do not. From time to time I still have the
>> Windows 98 install that's sitting in a corner of my disk throw a fit
>> just by having set the BIOS from LBA to Large (meaning the geometry the
>> BIOS pretends the disk has changes) for example. Old DOS installs that
>> I keep around for the purpose of hardware testing with the originally
>> supplied drivers make for even more of a "don't touch, don't touch!"
>> thing -- various version of DOS throw fits for various reasons.
>
> This is true, but that's due to the fundamentally broken nature of CHS.
> You need them to boot, and that's about it. I will say up front that I
> don't particularly care about legacy operating system such as DOS,
> Windows 98, or Minix 3. So the idea of simply having the number of heads
> and sectors in the partition header is that we can reconstruct CHS fields
> such that it is likely with modern hardware you will get it right.
Well, I still don't believe this all to be a great idea but it was sort of
fun so the attached does largely what you want -- build a list of all data
partitions.
The heads/sectors fields it for now just gets from the HDIO_GETGEO call. A
better source would be guessing the values from the partition table itself
but that _also_ doesn't make too much sense. If you're reconstructing a
sanitized version of the table anyway, it makes better sense to reconstruct
it with the values HDIO_GETGEO returns at restoration time.
I kept your suggested format, but in fact, the 64-bit "start" value seems
not very useful if we're getting the value from a 32-bit field in the old
partition tables anyway. With that shrunk down to 32-bit again, there would
be enough room for the complete partition table entry...
> For ancient systems that do all sorts of weird things such as ECHS,
> etc., yeah, you're pretty much doomed, and the bigger danger comes
> from futzing with BIOS settings, et. al. But it's 2007, gosh darn it!
> "Here's a quarter, kid, buy yourself a real computer". :-)
Thanks, but real computers won't host my ISA cards...
> Yes, I'm very aware of the extended partitioning scheme mess. What I
> was proposing to back up here is only the real partitions, not the
> fake extended partitions. The idea is to store *just* enough
> information so that a partition table manager can recover the
> partition tables in such a way that the original filesystem
> information can be recovered.
This should do I guess. It enters all data partitions into the list, in the
order in which they are encountered and sets a flag to signify that a
partition was a logical rather than primary. Another option would be to just
reserve the first 4 entries for the primaries and the rest for the logicals
but this saves entries if there are fewer than 4 primaries and was in fact
easier...
The program enters partitions in what should be the same order as Linux
itself does. Primaries from slot 0 to 3 as normal (but not backed up to
entry 0 to 3 as said -- the LOGICAL flag indentifies them), extended
partitions in the MBR in the order as encountered, with the logicals in the
second-level table as encountered, and following only the first extented in
the second-level table.
Made it into a generic C program -- didn't look at e2fsprogs sources yet.
Need to be off now and haven't yet stared at this as long as I'd like so
don't slap me if I've left a few bugs in (although it seems to work nicely).
The program dumps the backup sector to stdout -- it's ofcourse easy to
change it to print the entries out so they're easy to compare against, say,
"fdisk -l -us".
Oh, and once you've looked at it, please throw it away. As said, I still
don't think it's a great idea ;-)
Rene.
[-- Attachment #2: backup.c --]
[-- Type: text/plain, Size: 3535 bytes --]
/*
* Public Domain 2007, Rene Herman
*
* gcc -W -Wall -DTEST -D_LARGEFILE64_SOURCE -o backup backup.c
*
*/
#include <stdlib.h>
enum {
DOS_EXTENDED = 0x05,
WIN98_EXTENDED = 0x0f,
LINUX_EXTENDED = 0x85,
};
struct partition {
unsigned char boot_ind;
unsigned char __1[3];
unsigned char sys_ind;
unsigned char __2[3];
unsigned int start;
unsigned int size;
} __attribute__((packed));
struct entry {
unsigned char flags;
unsigned char type;
unsigned short __1;
unsigned long long start;
unsigned int size;
} __attribute__((packed));
enum {
ENTRY_FLAG_LOGICAL = 0x01,
ENTRY_FLAG_BOOTABLE = 0x80,
};
struct backup {
unsigned char signature[8];
unsigned short type;
unsigned char heads;
unsigned char sectors;
unsigned char count;
unsigned char __1[3];
struct entry table[31];
} __attribute__((packed));
#define BACKUP_SIGNATURE "PARTBAK1"
enum {
BACKUP_TYPE_MBR = 1,
};
struct backup backup = {
.signature = BACKUP_SIGNATURE,
.type = BACKUP_TYPE_MBR,
};
int is_extended(struct partition *entry)
{
int ret = 0;
switch (entry->sys_ind) {
case DOS_EXTENDED:
case WIN98_EXTENDED:
case LINUX_EXTENDED:
ret = 1;
}
return ret;
}
unsigned char *get_sector(unsigned int n);
void put_sector(unsigned char *sector);
int do_sector(unsigned int offset, unsigned int start)
{
unsigned char *sector;
struct partition *partition;
struct partition *extended = NULL;
start += offset;
sector = get_sector(start);
if (!sector)
return -1;
if (sector[510] != 0x55 || sector[511] != 0xaa) {
put_sector(sector);
return -1;
}
partition = (struct partition *)(sector + 510 - 4 * sizeof *partition);
do {
struct entry *entry;
if (!partition->size)
continue;
if (is_extended(partition)) {
if (!offset)
do_sector(partition->start, 0);
else if (!extended)
extended = partition;
continue;
}
entry = backup.table + backup.count++;
entry->flags = partition->boot_ind;
if (offset)
entry->flags |= ENTRY_FLAG_LOGICAL;
entry->type = partition->sys_ind;
entry->start = start + partition->start;
entry->size = partition->size;
} while (++partition < (struct partition *)(sector + 510));
if (extended)
do_sector(offset, extended->start);
put_sector(sector);
return 0;
}
#ifdef TEST
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/hdreg.h>
int fd;
unsigned char *get_sector(unsigned int n)
{
unsigned char *sector = malloc(512);
if (!sector)
return NULL;
if (lseek64(fd, (off64_t)n << 9, SEEK_SET) < 0)
goto free;
if (read(fd, sector, 512) != 512) {
free:
free(sector);
sector = NULL;
}
return sector;
}
void put_sector(unsigned char *sector)
{
free(sector);
}
int main(int argc, char *argv[])
{
struct stat buf;
struct hd_geometry geometry;
if (argc != 2) {
printf("%s <blkdev>\n", argv[0]);
return EXIT_FAILURE;
}
fd = open(argv[1], O_RDONLY);
if (fd < 0) {
perror("open");
return EXIT_FAILURE;
}
if (fstat(fd, &buf) < 0 || !S_ISBLK(buf.st_mode)) {
perror("stat");
return EXIT_FAILURE;
}
if (ioctl(fd, HDIO_GETGEO, &geometry) == 0) {
backup.heads = geometry.heads;
backup.sectors = geometry.sectors;
}
if (do_sector(0, 0) < 0)
return EXIT_FAILURE;
if (close(fd) < 0) {
perror("close");
return EXIT_FAILURE;
}
if (write(STDOUT_FILENO, &backup, sizeof backup) != sizeof backup) {
perror("write");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
#endif
next prev parent reply other threads:[~2007-07-22 9:11 UTC|newest]
Thread overview: 39+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-07-20 5:13 [RFH] Partion table recovery Al Boldi
2007-07-20 5:20 ` Dave Young
2007-07-20 5:57 ` Dave Young
2007-07-20 11:29 ` [RFH] Partition " Al Boldi
2007-07-20 5:25 ` [RFH] Partion " James Lamanna
2007-07-20 7:00 ` Jan-Benedict Glaw
2007-07-20 11:29 ` [RFH] Partition " Al Boldi
2007-07-20 11:53 ` Anton Altaparmakov
2007-07-20 5:35 ` [RFH] Partion " Willy Tarreau
2007-07-20 5:44 ` Dave Young
2007-07-20 7:03 ` Jan Engelhardt
2007-07-20 11:29 ` [RFH] Partition " Al Boldi
2007-07-20 11:39 ` Jan-Benedict Glaw
2007-07-20 12:22 ` Al Boldi
2007-07-20 12:29 ` Rene Herman
2007-07-20 16:06 ` Theodore Tso
2007-07-21 17:54 ` Rene Herman
[not found] ` <20070722011141.GJ26752@thunk.org>
2007-07-22 4:10 ` Al Boldi
2007-07-22 16:28 ` Theodore Tso
2007-07-22 19:05 ` Al Boldi
2007-07-22 21:23 ` Indan Zupancic
2007-07-23 8:15 ` Rene Herman
2007-07-23 8:41 ` Jan-Benedict Glaw
2007-07-23 10:54 ` Rene Herman
2007-07-23 12:39 ` Rene Herman
2007-07-23 13:15 ` Jan-Benedict Glaw
2007-07-23 13:32 ` Rene Herman
2007-07-23 20:22 ` Bill Davidsen
2007-07-23 13:58 ` Theodore Tso
2007-07-24 4:08 ` Rene Herman
2007-07-22 9:11 ` Rene Herman [this message]
[not found] ` <20070722163934.GB20174@thunk.org>
[not found] ` <46A45A01.5050709@gmail.com>
2007-07-23 13:48 ` Theodore Tso
2007-07-24 3:41 ` Rene Herman
2007-07-20 6:47 ` [RFH] Partion " Jeffrey V. Merkey
2007-07-20 11:29 ` [RFH] Partition " Al Boldi
2007-07-20 7:35 ` [RFH] Partion " Anton Altaparmakov
2007-07-21 19:40 ` Willy Tarreau
2007-07-23 20:08 ` Bill Davidsen
2007-07-24 3:45 ` Rene Herman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=46A31F55.2000009@gmail.com \
--to=rene.herman@gmail.com \
--cc=a1426z@gawab.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-raid@vger.kernel.org \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).