linux-raid.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
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

  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).