All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.