Sophie

Sophie

distrib > Mageia > 7 > i586 > by-pkgid > 00c7f3b98d0f686381db36d111461906 > files > 43

grub-0.97-48.mga7.src.rpm

[ Colin King ]
* debian/patches/uuid.diff: added uuid command, to select root device by
  uuid. Supports uuid booting from ext2, ext3, fat, vfat, jfs, ocfs,
  reiserfs, and xfs filesystems, based on a heavily-modified version of the
  udev volume_id lib by Kay Sievers <kay.sievers@vrfy.org>.  LP: #244141.
* Add uuid command to grub documenation

=== modified file 'Makefile.am'
--- grub-0.97.orig/Makefile.am	2004-04-23 13:39:01 +0000
+++ grub-0.97/Makefile.am	2008-07-09 17:23:44 +0000
@@ -1,4 +1,9 @@
 # Do not change this order if you don't know what you are doing.
 AUTOMAKE_OPTIONS = 1.7 gnu
-SUBDIRS = netboot stage2 stage1 lib grub util docs
+if UUID_SUPPORT
+SUBDIRS = libvolume_id netboot stage2 stage1 lib grub util docs 
+else
+SUBDIRS = netboot stage2 stage1 lib grub util docs 
+endif
+
 EXTRA_DIST = BUGS MAINTENANCE

=== modified file 'configure.ac'
--- grub-0.97.orig/configure.ac	2008-01-28 18:41:45 +0000
+++ grub-0.97/configure.ac	2008-07-09 17:23:44 +0000
@@ -56,6 +56,7 @@
 
 AC_CHECK_TOOL(CC, gcc)
 AC_PROG_CC
+AM_PROG_AS
 # We need this for older versions of Autoconf.
 _AM_DEPENDENCIES(CC)
 
@@ -605,6 +606,11 @@
   [  --disable-serial        disable serial terminal support])
 AM_CONDITIONAL(SERIAL_SUPPORT, test "x$enable_serial" != xno)
 
+dnl UUID scanning
+AC_ARG_ENABLE(uuid,
+  [  --disable-uuid          disable uuid scanning support])
+AM_CONDITIONAL(UUID_SUPPORT, test "x$enable_uuid" != xno)
+
 dnl Simulation of the slowness of a serial device.
 AC_ARG_ENABLE(serial-speed-simulation,
   [  --enable-serial-speed-simulation
@@ -666,5 +672,6 @@
 		 docs/Makefile lib/Makefile util/Makefile \
 		 grub/Makefile netboot/Makefile util/grub-image \
 		 util/grub-install util/grub-md5-crypt \
-		 util/grub-terminfo])
+		 util/grub-terminfo \
+		 libvolume_id/Makefile])
 AC_OUTPUT

=== modified file 'grub/Makefile.am'
--- grub-0.97.orig/grub/Makefile.am	2005-02-02 20:40:05 +0000
+++ grub-0.97/grub/Makefile.am	2008-07-09 17:23:44 +0000
@@ -16,4 +16,9 @@
 AM_CFLAGS = $(GRUB_CFLAGS)
 
 grub_SOURCES = main.c asmstub.c
-grub_LDADD = ../stage2/libgrub.a  ../lib/libcommon.a $(GRUB_LIBS)
+
+if UUID_SUPPORT
+grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a ../libvolume_id/libvolume_id.a $(GRUB_LIBS)
+else
+grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a $(GRUB_LIBS)
+endif

=== added directory 'libvolume_id'
=== added file 'libvolume_id/Makefile.am'
--- grub-0.97.orig/libvolume_id/Makefile.am	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/Makefile.am	2008-07-15 12:31:43 +0000
@@ -0,0 +1,27 @@
+noinst_LIBRARIES = libvolume_id.a
+
+AM_CFLAGS = $(STAGE2_CFLAGS) -I$(top_srcdir)/stage2 -I$(top_srcdir)/stage1
+
+LIBVOLUME_ID_FS_SUPPORTED = 	ext.c fat.c hfs.c jfs.c  \
+			 	luks.c ntfs.c ocfs.c reiserfs.c \
+			 	xfs.c 
+
+LIBVOLUME_ID_FS_UNSUPPORTED = 	cramfs.c gfs.c hpfs.c iso9660.c \
+			 	lvm.c minix.c romfs.c squashfs.c \
+				sysv.c udf.c ufs.c vxfs.c
+
+LIBVOLUME_ID_RAID_SUPPORTED = 	ddf_raid.c 
+
+LIBVOLUME_ID_RAID_UNSUPPORTED = adaptec_raid.c highpoint.c isw_raid.c \
+				jmicron_raid.c linux_raid.c lsi_raid.c \
+				nvidia_raid.c promise_raid.c silicon_raid.c \
+				via_raid.c 
+
+LIBVOLUME_ID_MISC_UNSUPPORTED = linux_swap.c netware.c
+
+libvolume_id_a_SOURCES = 	$(LIBVOLUME_ID_FS_SUPPORTED) \
+   			 	$(LIBVOLUME_ID_RAID_SUPPORTED) \
+				$(LIBVOLUME_ID_FS_UNSUPPORTED) \
+				$(LIBVOLUME_ID_RAID_UNSUPPORTED) \
+			 	volume_id.h volume_id.c util.c util.h misc.c 
+

=== added file 'libvolume_id/adaptec_raid.c'
--- grub-0.97.orig/libvolume_id/adaptec_raid.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/adaptec_raid.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,107 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct adaptec_meta {
+	uint32_t	b0idcode;
+	uint8_t		lunsave[8];
+	uint16_t	sdtype;
+	uint16_t	ssavecyl;
+	uint8_t		ssavehed;
+	uint8_t		ssavesec;
+	uint8_t		sb0flags;
+	uint8_t		jbodEnable;
+	uint8_t		lundsave;
+	uint8_t		svpdirty;
+	uint16_t	biosInfo;
+	uint16_t	svwbskip;
+	uint16_t	svwbcln;
+	uint16_t	svwbmax;
+	uint16_t	res3;
+	uint16_t	svwbmin;
+	uint16_t	res4;
+	uint16_t	svrcacth;
+	uint16_t	svwcacth;
+	uint16_t	svwbdly;
+	uint8_t		svsdtime;
+	uint8_t		res5;
+	uint16_t	firmval;
+	uint16_t	firmbln;
+	uint32_t	firmblk;
+	uint32_t	fstrsvrb;
+	uint16_t	svBlockStorageTid;
+	uint16_t	svtid;
+	uint8_t		svseccfl;
+	uint8_t		res6;
+	uint8_t		svhbanum;
+	uint8_t		resver;
+	uint32_t	drivemagic;
+	uint8_t		reserved[20];
+	uint8_t		testnum;
+	uint8_t		testflags;
+	uint16_t	maxErrorCount;
+	uint32_t	count;
+	uint32_t	startTime;
+	uint32_t	interval;
+	uint8_t		tstxt0;
+	uint8_t		tstxt1;
+	uint8_t		serNum[32];
+	uint8_t		res8[102];
+	uint32_t	fwTestMagic;
+	uint32_t	fwTestSeqNum;
+	uint8_t		fwTestRes[8];
+	uint8_t		smagic[4];
+	uint32_t	raidtbl;
+	uint16_t	raidline;
+	uint8_t		res9[0xF6];
+} PACKED;
+
+int volume_id_probe_adaptec_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	uint64_t meta_off;
+	struct adaptec_meta *ad;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	if (size < 0x10000)
+		return -1;
+
+	meta_off = ((size / 0x200)-1) * 0x200;
+	buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	ad = (struct adaptec_meta *) buf;
+	if (memcmp((char*)ad->smagic, "DPTM", 4) != 0)
+		return -1;
+
+	if (ad->b0idcode != be32_to_cpu(0x37FC4D1E))
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	sprintf(id->type_version, "%u", ad->resver);
+	id->type = "adaptec_raid_member";
+
+	return 0;
+}

=== added file 'libvolume_id/cramfs.c'
--- grub-0.97.orig/libvolume_id/cramfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/cramfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,60 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct cramfs_super {
+	uint8_t		magic[4];
+	uint32_t	size;
+	uint32_t	flags;
+	uint32_t	future;
+	uint8_t		signature[16];
+	struct cramfs_info {
+		uint32_t	crc;
+		uint32_t	edition;
+		uint32_t	blocks;
+		uint32_t	files;
+	} PACKED info;
+	uint8_t		name[16];
+} PACKED;
+
+int volume_id_probe_cramfs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct cramfs_super *cs;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	cs = (struct cramfs_super *) volume_id_get_buffer(id, off, 0x200);
+	if (cs == NULL)
+		return -1;
+
+	if (memcmp((char*)cs->magic, "\x45\x3d\xcd\x28", 4) == 0 || memcmp((char*)cs->magic, "\x28\xcd\x3d\x45", 4) == 0) {
+		volume_id_set_label_raw(id, cs->name, 16);
+		volume_id_set_label_string(id, cs->name, 16);
+
+		volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+		id->type = "cramfs";
+		return 0;
+	}
+
+	return -1;
+}

=== added file 'libvolume_id/ddf_raid.c'
--- grub-0.97.orig/libvolume_id/ddf_raid.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/ddf_raid.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,60 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2007 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+/* http://www.snia.org/standards/home */
+
+#define DDF_HEADER			0xDE11DE11
+#define DDF_GUID_LENGTH			24
+#define DDF_REV_LENGTH			8
+
+static struct ddf_header {
+	uint32_t	signature;
+	uint32_t	crc;
+	uint8_t		guid[DDF_GUID_LENGTH];
+	uint8_t		ddf_rev[DDF_REV_LENGTH];
+} PACKED *ddf;
+
+int volume_id_probe_ddf_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	uint64_t ddf_off = ((size / 0x200)-1) * 0x200;
+	const uint8_t *buf;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+	if (size < 0x10000)
+		return -1;
+
+	buf = volume_id_get_buffer(id, off + ddf_off, 0x200);
+	if (buf == NULL)
+		return -1;
+	ddf = (struct ddf_header *) buf;
+
+	if (ddf->signature != cpu_to_be32(DDF_HEADER))
+		return -1;
+
+	volume_id_set_uuid(id, ddf->guid, DDF_GUID_LENGTH, UUID_STRING);
+	strcpy(id->type_version, (char*) ddf->ddf_rev);
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	id->type = "ddf_raid_member";
+	return 0;
+}

=== added file 'libvolume_id/ext.c'
--- grub-0.97.orig/libvolume_id/ext.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/ext.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,129 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct ext2_super_block {
+	uint32_t	s_inodes_count;
+	uint32_t	s_blocks_count;
+	uint32_t	s_r_blocks_count;
+	uint32_t	s_free_blocks_count;
+	uint32_t	s_free_inodes_count;
+	uint32_t	s_first_data_block;
+	uint32_t	s_log_block_size;
+	uint32_t	s_log_frag_size;
+	uint32_t	s_blocks_per_group;
+	uint32_t	s_frags_per_group;
+	uint32_t	s_inodes_per_group;
+	uint32_t	s_mtime;
+	uint32_t	s_wtime;
+	uint16_t	s_mnt_count;
+	uint16_t	s_max_mnt_count;
+	uint16_t	s_magic;
+	uint16_t	s_state;
+	uint16_t	s_errors;
+	uint16_t	s_minor_rev_level;
+	uint32_t	s_lastcheck;
+	uint32_t	s_checkinterval;
+	uint32_t	s_creator_os;
+	uint32_t	s_rev_level;
+	uint16_t	s_def_resuid;
+	uint16_t	s_def_resgid;
+	uint32_t	s_first_ino;
+	uint16_t	s_inode_size;
+	uint16_t	s_block_group_nr;
+	uint32_t	s_feature_compat;
+	uint32_t	s_feature_incompat;
+	uint32_t	s_feature_ro_compat;
+	uint8_t		s_uuid[16];
+	uint8_t		s_volume_name[16];
+} PACKED;
+
+#define EXT_SUPER_MAGIC				0xEF53
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV	0x0008
+#define EXT3_FEATURE_INCOMPAT_EXTENTS		0x0040
+#define EXT4_FEATURE_INCOMPAT_64BIT		0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP		0x0100
+
+#define EXT_SUPERBLOCK_OFFSET			0x400
+
+#define EXT3_MIN_BLOCK_SIZE			0x400
+#define EXT3_MAX_BLOCK_SIZE			0x1000
+
+int volume_id_probe_ext(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct ext2_super_block *es;
+	size_t bsize;
+	uint32_t feature_compat;
+	uint32_t feature_incompat;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	es = (struct ext2_super_block *) volume_id_get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200);
+	if (es == NULL)
+		return -1;
+
+	if (es->s_magic != cpu_to_le16(EXT_SUPER_MAGIC))
+		return -1;
+
+	bsize = 0x400 << le32_to_cpu(es->s_log_block_size);
+	dbg("ext blocksize 0x%zx", bsize);
+	if (bsize < EXT3_MIN_BLOCK_SIZE || bsize > EXT3_MAX_BLOCK_SIZE) {
+		dbg("invalid ext blocksize");
+		return -1;
+	}
+
+	volume_id_set_label_raw(id, es->s_volume_name, 16);
+	volume_id_set_label_string(id, es->s_volume_name, 16);
+	volume_id_set_uuid(id, es->s_uuid, 0, UUID_DCE);
+	sprintf(id->type_version, "%u.%u",
+		 le32_to_cpu(es->s_rev_level), le16_to_cpu(es->s_minor_rev_level));
+
+	feature_compat = le32_to_cpu(es->s_feature_compat);
+	feature_incompat = le32_to_cpu(es->s_feature_incompat);
+
+	/* check for external journal device */
+	if ((feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) != 0) {
+		volume_id_set_usage(id, VOLUME_ID_OTHER);
+		id->type = "jbd";
+		goto out;
+	}
+
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+
+	if ((feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) != 0 ||
+	    (feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) != 0 ||
+	    (feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) != 0) {
+		id->type = "ext4";
+		goto out;
+	}
+
+	if ((feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) {
+		id->type = "ext3";
+		goto out;
+	}
+
+	id->type = "ext2";
+
+out:
+	return 0;
+}

=== added file 'libvolume_id/fat.c'
--- grub-0.97.orig/libvolume_id/fat.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/fat.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,482 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004-2007 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2007 Ryan Lortie <desrt@desrt.ca>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+#define FAT12_MAX			0xff5
+#define FAT16_MAX			0xfff5
+#define FAT_ATTR_VOLUME_ID		0x08
+#define FAT_ATTR_DIR			0x10
+#define FAT_ATTR_LONG_NAME		0x0f
+#define FAT_ATTR_MASK			0x3f
+#define FAT_ENTRY_FREE			0xe5
+
+#define VFAT_LFN_SEQ_MASK		0x3f
+#define VFAT_LFN_SEQ_LAST		0x40
+#define VFAT_LFN_SEQ_MAX		20
+#define VFAT_LFN_CHARS_PER_ENTRY	(5 + 6 + 2)
+#define VFAT_LOWERCASE_NAME		0x10
+#define VFAT_LOWERCASE_EXT		0x08
+
+struct vfat_super_block {
+	uint8_t		boot_jump[3];
+	uint8_t		sysid[8];
+	uint16_t	sector_size;
+	uint8_t		sectors_per_cluster;
+	uint16_t	reserved;
+	uint8_t		fats;
+	uint16_t	dir_entries;
+	uint16_t	sectors;
+	uint8_t		media;
+	uint16_t	fat_length;
+	uint16_t	secs_track;
+	uint16_t	heads;
+	uint32_t	hidden;
+	uint32_t	total_sect;
+	union {
+		struct fat_super_block {
+			uint8_t		unknown[3];
+			uint8_t		serno[4];
+			uint8_t		label[11];
+			uint8_t		magic[8];
+			uint8_t		dummy2[192];
+			uint8_t		pmagic[2];
+		} PACKED fat;
+		struct fat32_super_block {
+			uint32_t	fat32_length;
+			uint16_t	flags;
+			uint8_t		version[2];
+			uint32_t	root_cluster;
+			uint16_t	fsinfo_sector;
+			uint16_t	backup_boot;
+			uint16_t	reserved2[6];
+			uint8_t		unknown[3];
+			uint8_t		serno[4];
+			uint8_t		label[11];
+			uint8_t		magic[8];
+			uint8_t		dummy2[164];
+			uint8_t		pmagic[2];
+		} PACKED fat32;
+	} PACKED type;
+} PACKED;
+
+struct fat32_fsinfo {
+	uint8_t signature1[4];
+	uint32_t reserved1[120];
+	uint8_t signature2[4];
+	uint32_t free_clusters;
+	uint32_t next_cluster;
+	uint32_t reserved2[4];
+} PACKED;
+
+struct vfat_dir_entry {
+	uint8_t		name[11];
+	uint8_t		attr;
+	uint8_t		lowercase;
+	uint8_t		fine_time_creat;
+	uint16_t	time_creat;
+	uint16_t	date_creat;
+	uint16_t	date_acc;
+	uint16_t	cluster_high;
+	uint16_t	time_write;
+	uint16_t	date_write;
+	uint16_t	cluster_low;
+	uint32_t	size;
+} PACKED;
+
+
+struct vfat_lfn_entry {
+	uint8_t		seq;
+	uint16_t	name0[5];
+	uint8_t		attr;
+	uint8_t		reserved;
+	uint8_t		cksum;
+	uint16_t	name1[6];
+	uint16_t	cluster;
+	uint16_t	name2[2];
+} PACKED;
+
+static uint8_t fat_lfn_checksum(const uint8_t name[11])
+{
+	uint8_t cksum = 0;
+	int i;
+
+	/* http://en.wikipedia.org/wiki/File_Allocation_Table */
+	for (i = 0; i < 11; i++)
+		cksum = ((cksum & 1) ? 0x80 : 0) + (cksum >> 1) + name[i];
+
+	return cksum;
+}
+
+static size_t fat_read_lfn(uint8_t *filename, size_t fnsize,
+			   struct vfat_dir_entry *direntry,
+			   struct vfat_dir_entry *entry)
+{
+	uint8_t buffer[VFAT_LFN_SEQ_MAX * VFAT_LFN_CHARS_PER_ENTRY * 2];
+	uint8_t expected_seq = 1;
+	uint8_t cksum;
+	size_t len = 0;
+	size_t fnlen = 0;
+
+	cksum = fat_lfn_checksum(entry->name);
+
+	while (--entry >= direntry) {
+		struct vfat_lfn_entry *lfn = (struct vfat_lfn_entry *) entry;
+
+		if (expected_seq > VFAT_LFN_SEQ_MAX)
+			break;
+
+		if ((lfn->attr & FAT_ATTR_MASK) != FAT_ATTR_LONG_NAME)
+			break;
+
+		if (lfn->cksum != cksum)
+			break;
+
+		if ((lfn->seq & VFAT_LFN_SEQ_MASK) != expected_seq++)
+			break;
+
+		if (lfn->cluster != 0)
+			break;
+
+		/* extra paranoia -- should never happen */
+		if (len + sizeof(lfn->name0) + sizeof(lfn->name1) +
+		    sizeof(lfn->name2) > sizeof(buffer))
+			break;
+
+		memcpy (&buffer[len], lfn->name0, sizeof(lfn->name0));
+		len += sizeof(lfn->name0);
+		memcpy (&buffer[len], lfn->name1, sizeof(lfn->name1));
+		len += sizeof(lfn->name1);
+		memcpy (&buffer[len], lfn->name2, sizeof(lfn->name2));
+		len += sizeof(lfn->name2);
+
+		if (lfn->seq & VFAT_LFN_SEQ_LAST) {
+			fnlen = volume_id_set_unicode16(filename, fnsize, buffer, LE, len);
+			break;
+		}
+	}
+
+	return fnlen;
+}
+
+static size_t fat_read_filename(uint8_t *filename, size_t fnsize,
+				struct vfat_dir_entry *direntry, struct vfat_dir_entry *entry)
+{
+	size_t len;
+	int i;
+
+	/* check if maybe we have LFN entries */
+	len = fat_read_lfn(filename, fnsize, direntry, entry);
+	if (len > 0)
+		goto out;
+
+	/* else, read the normal 8.3 name */
+	for (i = 0; i < 11; i++) {
+		if (entry->lowercase & ((i < 8) ? VFAT_LOWERCASE_NAME : VFAT_LOWERCASE_EXT))
+			filename[i] = tolower(entry->name[i]);
+		else
+			filename[i] = entry->name[i];
+	}
+	len = 11;
+
+out:
+	filename[len] = '\0';
+	return len;
+}
+
+/* fills filename, returns string length */
+static size_t get_fat_attr_volume_id(uint8_t *filename, size_t fnsize,
+				     struct vfat_dir_entry *direntry, unsigned int count)
+{
+	unsigned int i;
+
+	for (i = 0; i < count; i++) {
+		/* end marker */
+		if (direntry[i].name[0] == 0x00) {
+			dbg("end of dir");
+			break;
+		}
+
+		/* empty entry */
+		if (direntry[i].name[0] == FAT_ENTRY_FREE)
+			continue;
+
+		/* long name */
+		if ((direntry[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)
+			continue;
+
+		if ((direntry[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
+			/* labels do not have file data */
+			if (direntry[i].cluster_high != 0 || direntry[i].cluster_low != 0)
+				continue;
+
+			dbg("found ATTR_VOLUME_ID id in root dir");
+			return fat_read_filename(filename, fnsize, direntry, &direntry[i]);
+		}
+
+		dbg("skip dir entry");
+	}
+
+	return 0;
+}
+
+int volume_id_probe_vfat(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	uint8_t filename[255 * 3];
+	struct vfat_super_block *vs;
+	struct vfat_dir_entry *direntry;
+	struct fat32_fsinfo *fsinfo;
+	uint16_t sector_size;
+	uint16_t dir_entries;
+	uint32_t sect_count;
+	uint16_t reserved;
+	uint32_t fat_size;
+	uint32_t root_cluster;
+	uint32_t dir_size;
+	uint32_t cluster_count;
+	uint16_t fat_length;
+	uint32_t fat32_length;
+	uint64_t root_start;
+	uint32_t start_data_sect;
+	uint16_t root_dir_entries;
+	uint16_t fsinfo_sect;
+	uint8_t *buf;
+	uint32_t buf_size;
+	uint32_t next;
+	int maxloop;
+	size_t fnlen;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	buf = volume_id_get_buffer(id, off, 0x400);
+	if (buf == NULL)
+		return -1;
+
+	/* check signature */
+	if (buf[510] != 0x55 || buf[511] != 0xaa)
+		return -1;
+
+	vs = (struct vfat_super_block *) buf;
+	if (memcmp((char*)vs->sysid, "NTFS", 4) == 0)
+		return -1;
+
+	/* believe only that's fat, don't trust the version */
+	if (memcmp((char*)vs->type.fat32.magic, "MSWIN", 5) == 0)
+		goto magic;
+
+	if (memcmp((char*)vs->type.fat32.magic, "FAT32   ", 8) == 0)
+		goto magic;
+
+	if (memcmp((char*)vs->type.fat.magic, "FAT16   ", 8) == 0)
+		goto magic;
+
+	if (memcmp((char*)vs->type.fat.magic, "MSDOS", 5) == 0)
+		goto magic;
+
+	if (memcmp((char*)vs->type.fat.magic, "FAT12   ", 8) == 0)
+		goto magic;
+
+	/* some old floppies don't have a magic, expect the boot jump address to match */
+	if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
+	     vs->boot_jump[0] != 0xe9)
+		return -1;
+
+magic:
+	/* reserverd sector count */
+	if (!vs->reserved)
+		return -1;
+
+	/* fat count */
+	if (!vs->fats)
+		return -1;
+
+	/* media check */
+	if (vs->media < 0xf8 && vs->media != 0xf0)
+		return -1;
+
+	/* cluster size check */
+	if (vs->sectors_per_cluster == 0 ||
+	    (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
+		return -1;
+
+	/* sector size check */
+	sector_size = le16_to_cpu(vs->sector_size);
+	if (sector_size == 0 || ((sector_size & (sector_size-1)) != 0))
+		return -1;
+
+	dbg("sector_size 0x%x", sector_size);
+	dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster);
+
+	dir_entries = le16_to_cpu(vs->dir_entries);
+	reserved = le16_to_cpu(vs->reserved);
+	dbg("reserved 0x%x", reserved);
+
+	sect_count = le16_to_cpu(vs->sectors);
+	if (sect_count == 0)
+		sect_count = le32_to_cpu(vs->total_sect);
+	dbg("sect_count 0x%x", sect_count);
+
+	fat_length = le16_to_cpu(vs->fat_length);
+	dbg("fat_length 0x%x", fat_length);
+	fat32_length = le32_to_cpu(vs->type.fat32.fat32_length);
+	dbg("fat32_length 0x%x", fat32_length);
+
+	if (fat_length)
+		fat_size = fat_length * vs->fats;
+	else if (fat32_length)
+		fat_size = fat32_length * vs->fats;
+	else
+		return -1;
+	dbg("fat_size 0x%x", fat_size);
+
+	dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
+			(sector_size-1)) / sector_size;
+	dbg("dir_size 0x%x", dir_size);
+
+	cluster_count = sect_count - (reserved + fat_size + dir_size);
+	cluster_count /= vs->sectors_per_cluster;
+	dbg("cluster_count 0x%x", cluster_count);
+
+	/* must be FAT32 */
+	if (!fat_length && fat32_length)
+		goto fat32;
+
+	/* cluster_count tells us the format */
+	if (cluster_count < FAT12_MAX)
+		strcpy(id->type_version, "FAT12");
+	else if (cluster_count < FAT16_MAX)
+		strcpy(id->type_version, "FAT16");
+	else
+		goto fat32;
+
+	/* the label may be an attribute in the root directory */
+	root_start = (reserved + fat_size) * sector_size;
+	dbg("root dir start 0x%llx", (unsigned long long) root_start);
+	root_dir_entries = le16_to_cpu(vs->dir_entries);
+	dbg("expected entries 0x%x", root_dir_entries);
+
+	buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
+	buf = volume_id_get_buffer(id, off + root_start, buf_size);
+	if (buf == NULL)
+		goto found;
+
+	direntry = (struct vfat_dir_entry*) buf;
+
+	fnlen = get_fat_attr_volume_id(filename, sizeof(filename), direntry, root_dir_entries);
+
+	vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
+	if (vs == NULL)
+		return -1;
+
+	if (fnlen > 0 && memcmp((char*)filename, "NO NAME    ", 11) != 0) {
+		volume_id_set_label_raw(id, filename, fnlen);
+		volume_id_set_label_string(id, filename, fnlen);
+	} else if (memcmp((char*)vs->type.fat.label, "NO NAME    ", 11) != 0) {
+		volume_id_set_label_raw(id, vs->type.fat.label, 11);
+		volume_id_set_label_string(id, vs->type.fat.label, 11);
+	}
+	volume_id_set_uuid(id, vs->type.fat.serno, 0, UUID_DOS);
+	goto found;
+
+fat32:
+	/* FAT32 should have a valid signature in the fsinfo block */
+	fsinfo_sect = le16_to_cpu(vs->type.fat32.fsinfo_sector);
+	buf = volume_id_get_buffer(id, off + (fsinfo_sect * sector_size), 0x200);
+	if (buf == NULL)
+		return -1;
+	fsinfo = (struct fat32_fsinfo *) buf;
+	if (memcmp((char*)fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0)
+		return -1;
+	if (memcmp((char*)fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0)
+		return -1 ;
+
+	vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
+	if (vs == NULL)
+		return -1;
+
+	strcpy(id->type_version, "FAT32");
+
+	/* FAT32 root dir is a cluster chain like any other directory */
+	buf_size = vs->sectors_per_cluster * sector_size;
+	root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
+	dbg("root dir cluster %u", root_cluster);
+	start_data_sect = reserved + fat_size;
+
+	next = root_cluster;
+	maxloop = 100;
+	while (--maxloop) {
+		uint32_t next_sect_off;
+		uint64_t next_off;
+		uint64_t fat_entry_off;
+		int count;
+
+		dbg("next cluster %u", next);
+		next_sect_off = (next - 2) * vs->sectors_per_cluster;
+		next_off = (start_data_sect + next_sect_off) * sector_size;
+		dbg("cluster offset 0x%llx", (unsigned long long) next_off);
+
+		/* get cluster */
+		buf = volume_id_get_buffer(id, off + next_off, buf_size);
+		if (buf == NULL)
+			goto found;
+
+		direntry = (struct vfat_dir_entry*) buf;
+		count = buf_size / sizeof(struct vfat_dir_entry);
+		dbg("expected entries 0x%x", count);
+
+		fnlen = get_fat_attr_volume_id(filename, sizeof(filename), direntry, count);
+		if (fnlen > 0)
+			break;
+
+		/* get FAT entry */
+		fat_entry_off = (reserved * sector_size) + (next * sizeof(uint32_t));
+		buf = volume_id_get_buffer(id, off + fat_entry_off, buf_size);
+		if (buf == NULL)
+			goto found;
+
+		/* set next cluster */
+		next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff;
+		if (next < 2 || next >= 0x0ffffff0)
+			break;
+	}
+	if (maxloop == 0)
+		dbg("reached maximum follow count of root cluster chain, give up");
+
+	vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
+	if (vs == NULL)
+		return -1;
+
+	if (fnlen > 0 && memcmp((char*)filename, "NO NAME    ", 11) != 0) {
+		volume_id_set_label_raw(id, filename, fnlen);
+		volume_id_set_label_string(id, filename, fnlen);
+	} else if (memcmp((char*)vs->type.fat32.label, "NO NAME    ", 11) != 0) {
+		volume_id_set_label_raw(id, vs->type.fat32.label, 11);
+		volume_id_set_label_string(id, vs->type.fat32.label, 11);
+	}
+	volume_id_set_uuid(id, vs->type.fat32.serno, 0, UUID_DOS);
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "vfat";
+
+	return 0;
+}

=== added file 'libvolume_id/gfs.c'
--- grub-0.97.orig/libvolume_id/gfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/gfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,115 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2006 Red Hat, Inc. <redhat.com>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+/* Common gfs/gfs2 constants: */
+#define GFS_MAGIC		0x01161970
+#define GFS_DEFAULT_BSIZE	4096
+#define GFS_SUPERBLOCK_OFFSET	(0x10 * GFS_DEFAULT_BSIZE)
+#define GFS_METATYPE_SB		1
+#define GFS_FORMAT_SB		100
+#define GFS_LOCKNAME_LEN	64
+
+/* gfs1 constants: */
+#define GFS_FORMAT_FS		1309
+#define GFS_FORMAT_MULTI	1401
+/* gfs2 constants: */
+#define GFS2_FORMAT_FS		1801
+#define GFS2_FORMAT_MULTI	1900
+
+struct gfs2_meta_header {
+	uint32_t mh_magic;
+	uint32_t mh_type;
+	uint64_t __pad0;          /* Was generation number in gfs1 */
+	uint32_t mh_format;
+	uint32_t __pad1;          /* Was incarnation number in gfs1 */
+};
+
+struct gfs2_inum {
+	uint64_t no_formal_ino;
+	uint64_t no_addr;
+};
+
+struct gfs2_sb {
+	struct gfs2_meta_header sb_header;
+
+	uint32_t sb_fs_format;
+	uint32_t sb_multihost_format;
+	uint32_t  __pad0;  /* Was superblock flags in gfs1 */
+
+	uint32_t sb_bsize;
+	uint32_t sb_bsize_shift;
+	uint32_t __pad1;   /* Was journal segment size in gfs1 */
+
+	struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */
+	struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */
+	struct gfs2_inum sb_root_dir;
+
+	char sb_lockproto[GFS_LOCKNAME_LEN];
+	char sb_locktable[GFS_LOCKNAME_LEN];
+	/* In gfs1, quota and license dinodes followed */
+} PACKED;
+
+static int volume_id_probe_gfs_generic(struct volume_id *id, uint64_t off, int vers)
+{
+	struct gfs2_sb *sbd;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	sbd = (struct gfs2_sb *)
+		volume_id_get_buffer(id, off + GFS_SUPERBLOCK_OFFSET, sizeof(struct gfs2_sb));
+	if (sbd == NULL)
+		return -1;
+
+	if (be32_to_cpu(sbd->sb_header.mh_magic) == GFS_MAGIC &&
+		be32_to_cpu(sbd->sb_header.mh_type) == GFS_METATYPE_SB &&
+		be32_to_cpu(sbd->sb_header.mh_format) == GFS_FORMAT_SB) {
+		if (vers == 1) {
+			if (be32_to_cpu(sbd->sb_fs_format) != GFS_FORMAT_FS ||
+				be32_to_cpu(sbd->sb_multihost_format) != GFS_FORMAT_MULTI)
+				return -1; /* not gfs1 */
+			id->type = "gfs";
+		}
+		else if (vers == 2) {
+			if (be32_to_cpu(sbd->sb_fs_format) != GFS2_FORMAT_FS ||
+				be32_to_cpu(sbd->sb_multihost_format) != GFS2_FORMAT_MULTI)
+				return -1; /* not gfs2 */
+			id->type = "gfs2";
+		}
+		else
+			return -1;
+		strcpy(id->type_version, "1");
+		volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+		return 0;
+	}
+	return -1;
+}
+
+int volume_id_probe_gfs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	return volume_id_probe_gfs_generic(id, off, 1);
+}
+
+int volume_id_probe_gfs2(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	return volume_id_probe_gfs_generic(id, off, 2);
+}

=== added file 'libvolume_id/hfs.c'
--- grub-0.97.orig/libvolume_id/hfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/hfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,318 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct hfs_finder_info{
+	uint32_t	boot_folder;
+	uint32_t	start_app;
+	uint32_t	open_folder;
+	uint32_t	os9_folder;
+	uint32_t	reserved;
+	uint32_t	osx_folder;
+	uint8_t		id[8];
+} PACKED;
+
+static struct hfs_mdb {
+	uint8_t		signature[2];
+	uint32_t	cr_date;
+	uint32_t	ls_Mod;
+	uint16_t	atrb;
+	uint16_t	nm_fls;
+	uint16_t	vbm_st;
+	uint16_t	alloc_ptr;
+	uint16_t	nm_al_blks;
+	uint32_t	al_blk_size;
+	uint32_t	clp_size;
+	uint16_t	al_bl_st;
+	uint32_t	nxt_cnid;
+	uint16_t	free_bks;
+	uint8_t		label_len;
+	uint8_t		label[27];
+	uint32_t	vol_bkup;
+	uint16_t	vol_seq_num;
+	uint32_t	wr_cnt;
+	uint32_t	xt_clump_size;
+	uint32_t	ct_clump_size;
+	uint16_t	num_root_dirs;
+	uint32_t	file_count;
+	uint32_t	dir_count;
+	struct hfs_finder_info finder_info;
+	uint8_t		embed_sig[2];
+	uint16_t	embed_startblock;
+	uint16_t	embed_blockcount;
+} PACKED *hfs;
+
+struct hfsplus_bnode_descriptor {
+	uint32_t	next;
+	uint32_t	prev;
+	uint8_t		type;
+	uint8_t		height;
+	uint16_t	num_recs;
+	uint16_t	reserved;
+} PACKED;
+
+struct hfsplus_bheader_record {
+	uint16_t	depth;
+	uint32_t	root;
+	uint32_t	leaf_count;
+	uint32_t	leaf_head;
+	uint32_t	leaf_tail;
+	uint16_t	node_size;
+} PACKED;
+
+struct hfsplus_catalog_key {
+	uint16_t	key_len;
+	uint32_t	parent_id;
+	uint16_t	unicode_len;
+	uint8_t		unicode[255 * 2];
+} PACKED;
+
+struct hfsplus_extent {
+	uint32_t	start_block;
+	uint32_t	block_count;
+} PACKED;
+
+#define HFSPLUS_EXTENT_COUNT		8
+struct hfsplus_fork {
+	uint64_t	total_size;
+	uint32_t	clump_size;
+	uint32_t	total_blocks;
+	struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+} PACKED;
+
+static struct hfsplus_vol_header {
+	uint8_t		signature[2];
+	uint16_t	version;
+	uint32_t	attributes;
+	uint32_t	last_mount_vers;
+	uint32_t	reserved;
+	uint32_t	create_date;
+	uint32_t	modify_date;
+	uint32_t	backup_date;
+	uint32_t	checked_date;
+	uint32_t	file_count;
+	uint32_t	folder_count;
+	uint32_t	blocksize;
+	uint32_t	total_blocks;
+	uint32_t	free_blocks;
+	uint32_t	next_alloc;
+	uint32_t	rsrc_clump_sz;
+	uint32_t	data_clump_sz;
+	uint32_t	next_cnid;
+	uint32_t	write_count;
+	uint64_t	encodings_bmp;
+	struct hfs_finder_info finder_info;
+	struct hfsplus_fork alloc_file;
+	struct hfsplus_fork ext_file;
+	struct hfsplus_fork cat_file;
+	struct hfsplus_fork attr_file;
+	struct hfsplus_fork start_file;
+} PACKED *hfsplus;
+
+#define HFS_SUPERBLOCK_OFFSET		0x400
+#define HFS_NODE_LEAF			0xff
+#define HFSPLUS_POR_CNID		1
+
+static void hfsid_set_uuid(struct volume_id *id, const uint8_t *hfs_id)
+{
+#if 0
+	MD5_CTX md5c;
+	static const uint8_t hash_init[16] = {
+		0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6,
+		0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
+	};
+	uint8_t uuid[16];
+
+	if (*((uint64_t *)hfs_id) == 0)
+		return;
+
+	MD5_Init(&md5c);
+	MD5_Update(&md5c, &hash_init, 16);
+	MD5_Update(&md5c, hfs_id, 8);
+	MD5_Final(uuid, &md5c);
+
+	uuid[6] = 0x30 | (uuid[6] & 0x0f);
+	uuid[8] = 0x80 | (uuid[8] & 0x3f);
+	volume_id_set_uuid(id, uuid, UUID_DCE);
+#endif
+
+	volume_id_set_uuid(id, hfs_id, 0, UUID_64BIT_BE);
+}
+
+int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	unsigned int blocksize;
+	unsigned int cat_block;
+	unsigned int ext_block_start;
+	unsigned int ext_block_count;
+	int ext;
+	unsigned int leaf_node_head;
+	unsigned int leaf_node_count;
+	unsigned int leaf_node_size;
+	unsigned int leaf_block;
+	uint64_t leaf_off;
+	unsigned int alloc_block_size;
+	unsigned int alloc_first_block;
+	unsigned int embed_first_block;
+	unsigned int record_count;
+	struct hfsplus_bnode_descriptor *descr;
+	struct hfsplus_bheader_record *bnode;
+	struct hfsplus_catalog_key *key;
+	unsigned int label_len;
+	struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
+	const uint8_t *buf;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+	if (buf == NULL)
+                return -1;
+
+	hfs = (struct hfs_mdb *) buf;
+	if (memcmp((char *)hfs->signature, "BD", 2) != 0)
+		goto checkplus;
+
+	/* it may be just a hfs wrapper for hfs+ */
+	if (memcmp((char *)hfs->embed_sig, "H+", 2) == 0) {
+		alloc_block_size = be32_to_cpu(hfs->al_blk_size);
+		dbg("alloc_block_size 0x%x", alloc_block_size);
+
+		alloc_first_block = be16_to_cpu(hfs->al_bl_st);
+		dbg("alloc_first_block 0x%x", alloc_first_block);
+
+		embed_first_block = be16_to_cpu(hfs->embed_startblock);
+		dbg("embed_first_block 0x%x", embed_first_block);
+
+		off += (alloc_first_block * 512) +
+		       (embed_first_block * alloc_block_size);
+		dbg("hfs wrapped hfs+ found at offset 0x%llx", (unsigned long long) off);
+
+		buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
+		if (buf == NULL)
+			return -1;
+		goto checkplus;
+	}
+
+	if (hfs->label_len > 0 && hfs->label_len < 28) {
+		volume_id_set_label_raw(id, hfs->label, hfs->label_len);
+		volume_id_set_label_string(id, hfs->label, hfs->label_len) ;
+	}
+
+	hfsid_set_uuid(id, hfs->finder_info.id);
+
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "hfs";
+
+	return 0;
+
+checkplus:
+	hfsplus = (struct hfsplus_vol_header *) buf;
+	if (memcmp((char *)hfsplus->signature, "H+", 2) == 0)
+		goto hfsplus;
+	if (memcmp((char *)hfsplus->signature, "HX", 2) == 0)
+		goto hfsplus;
+	return -1;
+
+hfsplus:
+	hfsid_set_uuid(id, hfsplus->finder_info.id);
+
+	blocksize = be32_to_cpu(hfsplus->blocksize);
+	dbg("blocksize %u", blocksize);
+
+	memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
+	cat_block = be32_to_cpu(extents[0].start_block);
+	dbg("catalog start block 0x%x", cat_block);
+
+	buf = volume_id_get_buffer(id, off + (cat_block * blocksize), 0x2000);
+	if (buf == NULL)
+		goto found;
+
+	bnode = (struct hfsplus_bheader_record *)
+		&buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+	leaf_node_head = be32_to_cpu(bnode->leaf_head);
+	dbg("catalog leaf node 0x%x", leaf_node_head);
+
+	leaf_node_size = be16_to_cpu(bnode->node_size);
+	dbg("leaf node size 0x%x", leaf_node_size);
+
+	leaf_node_count = be32_to_cpu(bnode->leaf_count);
+	dbg("leaf node count 0x%x", leaf_node_count);
+	if (leaf_node_count == 0)
+		goto found;
+
+	leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
+
+	/* get physical location */
+	for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
+		ext_block_start = be32_to_cpu(extents[ext].start_block);
+		ext_block_count = be32_to_cpu(extents[ext].block_count);
+		dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
+
+		if (ext_block_count == 0)
+			goto found;
+
+		/* this is our extent */
+		if (leaf_block < ext_block_count)
+			break;
+
+		leaf_block -= ext_block_count;
+	}
+	if (ext == HFSPLUS_EXTENT_COUNT)
+		goto found;
+	dbg("found block in extent %i", ext);
+
+	leaf_off = (ext_block_start + leaf_block) * blocksize;
+
+	buf = volume_id_get_buffer(id, off + leaf_off, leaf_node_size);
+	if (buf == NULL)
+		goto found;
+
+	descr = (struct hfsplus_bnode_descriptor *) buf;
+	dbg("descriptor type 0x%x", descr->type);
+
+	record_count = be16_to_cpu(descr->num_recs);
+	dbg("number of records %u", record_count);
+	if (record_count == 0)
+		goto found;
+
+	if (descr->type != HFS_NODE_LEAF)
+		goto found;
+
+	key = (struct hfsplus_catalog_key *)
+		&buf[sizeof(struct hfsplus_bnode_descriptor)];
+
+	dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
+	if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
+		goto found;
+
+	label_len = be16_to_cpu(key->unicode_len) * 2;
+	dbg("label unicode16 len %i", label_len);
+	volume_id_set_label_raw(id, key->unicode, label_len);
+	volume_id_set_label_unicode16(id, key->unicode, BE, label_len);
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "hfsplus";
+
+	return 0;
+}

=== added file 'libvolume_id/highpoint.c'
--- grub-0.97.orig/libvolume_id/highpoint.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/highpoint.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,91 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct hpt37x_meta {
+	uint8_t		filler1[32];
+	uint32_t	magic;
+} PACKED;
+
+struct hpt45x_meta {
+	uint32_t	magic;
+} PACKED;
+
+#define HPT37X_CONFIG_OFF		0x1200
+#define HPT37X_MAGIC_OK			0x5a7816f0
+#define HPT37X_MAGIC_BAD		0x5a7816fd
+
+#define HPT45X_MAGIC_OK			0x5a7816f3
+#define HPT45X_MAGIC_BAD		0x5a7816fd
+
+
+int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	struct hpt37x_meta *hpt;
+	uint32_t magic;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	buf = volume_id_get_buffer(id, off + HPT37X_CONFIG_OFF, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	hpt = (struct hpt37x_meta *) buf;
+	magic = le32_to_cpu(hpt->magic);
+	if (magic != HPT37X_MAGIC_OK && magic != HPT37X_MAGIC_BAD)
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	id->type = "highpoint_raid_member";
+
+	return 0;
+}
+
+int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	struct hpt45x_meta *hpt;
+	uint64_t meta_off;
+	uint32_t magic;
+
+	dbg("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	if (size < 0x10000)
+		return -1;
+
+	meta_off = ((size / 0x200)-11) * 0x200;
+	buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	hpt = (struct hpt45x_meta *) buf;
+	magic = le32_to_cpu(hpt->magic);
+	if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD)
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	id->type = "highpoint_raid_member";
+
+	return 0;
+}

=== added file 'libvolume_id/hpfs.c'
--- grub-0.97.orig/libvolume_id/hpfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/hpfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,51 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct hpfs_super
+{
+	uint8_t		magic[4];
+	uint8_t		version;
+} PACKED;
+
+#define HPFS_SUPERBLOCK_OFFSET			0x2000
+
+int volume_id_probe_hpfs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct hpfs_super *hs;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	hs = (struct hpfs_super *) volume_id_get_buffer(id, off + HPFS_SUPERBLOCK_OFFSET, 0x200);
+	if (hs == NULL)
+		return -1;
+
+	if (memcmp((char *)hs->magic, "\x49\xe8\x95\xf9", 4) == 0) {
+		sprintf(id->type_version, "%u", hs->version);
+
+		volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+		id->type = "hpfs";
+		return 0;
+	}
+
+	return -1;
+}

=== added file 'libvolume_id/iso9660.c'
--- grub-0.97.orig/libvolume_id/iso9660.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/iso9660.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,119 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+#define ISO_SUPERBLOCK_OFFSET		0x8000
+#define ISO_SECTOR_SIZE			0x800
+#define ISO_VD_OFFSET			(ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE)
+#define ISO_VD_PRIMARY			0x1
+#define ISO_VD_SUPPLEMENTARY		0x2
+#define ISO_VD_END			0xff
+#define ISO_VD_MAX			16
+
+struct iso_volume_descriptor {
+	uint8_t		type;
+	uint8_t		id[5];
+	uint8_t		version;
+	uint8_t		flags;
+	uint8_t		system_id[32];
+	uint8_t		volume_id[32];
+	uint8_t		unused[8];
+	uint8_t		space_size[8];
+	uint8_t		escape_sequences[8];
+} PACKED;
+
+struct high_sierra_volume_descriptor {
+	uint8_t		foo[8];
+	uint8_t		type;
+	uint8_t		id[5];
+	uint8_t		version;
+} PACKED;
+
+int volume_id_probe_iso9660(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	uint8_t *buf;
+	struct iso_volume_descriptor *is;
+	struct high_sierra_volume_descriptor *hs;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	buf = volume_id_get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	is = (struct iso_volume_descriptor *) buf;
+
+	if (memcmp((char*)is->id, "CD001", 5) == 0) {
+		int vd_offset;
+		int i;
+
+		dbg("read label from PVD");
+		volume_id_set_label_raw(id, is->volume_id, 32);
+		volume_id_set_label_string(id, is->volume_id, 32);
+
+		dbg("looking for SVDs");
+		vd_offset = ISO_VD_OFFSET;
+		for (i = 0; i < ISO_VD_MAX; i++) {
+			uint8_t svd_label[64];
+
+			is = (struct iso_volume_descriptor *) volume_id_get_buffer(id, off + vd_offset, 0x200);
+			if (is == NULL || is->type == ISO_VD_END)
+				break;
+			if (is->type != ISO_VD_SUPPLEMENTARY)
+				continue;
+
+			dbg("found SVD at offset 0x%llx", (unsigned long long) (off + vd_offset));
+			if (memcmp((char *)is->escape_sequences, "%/@", 3) == 0||
+			    memcmp((char *)is->escape_sequences, "%/C", 3) == 0||
+			    memcmp((char *)is->escape_sequences, "%/E", 3) == 0) {
+				dbg("Joliet extension found");
+				volume_id_set_unicode16(svd_label, sizeof(svd_label), is->volume_id, BE, 32);
+				if (memcmp((char *)id->label, (char *)svd_label, 16) == 0) {
+					dbg("SVD label is identical, use the possibly longer PVD one");
+					break;
+				}
+
+				volume_id_set_label_raw(id, is->volume_id, 32);
+				volume_id_set_label_string(id, svd_label, 32);
+				strcpy(id->type_version, "Joliet Extension");
+				goto found;
+			}
+			vd_offset += ISO_SECTOR_SIZE;
+		}
+		goto found;
+	}
+
+	hs = (struct high_sierra_volume_descriptor *) buf;
+
+	if (memcmp((char *)hs->id, "CDROM", 5) == 0) {
+		strcpy(id->type_version, "High Sierra");
+		goto found;
+	}
+
+	return -1;
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "iso9660";
+
+	return 0;
+}

=== added file 'libvolume_id/isw_raid.c'
--- grub-0.97.orig/libvolume_id/isw_raid.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/isw_raid.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,61 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct isw_meta {
+	uint8_t		sig[32];
+	uint32_t	check_sum;
+	uint32_t	mpb_size;
+	uint32_t	family_num;
+	uint32_t	generation_num;
+} PACKED;
+
+#define ISW_SIGNATURE		"Intel Raid ISM Cfg Sig. "
+
+
+int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	uint64_t meta_off;
+	struct isw_meta *isw;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	if (size < 0x10000)
+		return -1;
+
+	meta_off = ((size / 0x200)-2) * 0x200;
+	buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	isw = (struct isw_meta *) buf;
+	if (memcmp((char *)isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0)
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	memcpy(id->type_version, &isw->sig[sizeof(ISW_SIGNATURE)-1], 6);
+	id->type = "isw_raid_member";
+
+	return 0;
+}

=== added file 'libvolume_id/jfs.c'
--- grub-0.97.orig/libvolume_id/jfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/jfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,60 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct jfs_super_block {
+	uint8_t		magic[4];
+	uint32_t	version;
+	uint64_t	size;
+	uint32_t	bsize;
+	uint32_t	dummy1;
+	uint32_t	pbsize;
+	uint32_t	dummy2[27];
+	uint8_t		uuid[16];
+	uint8_t		label[16];
+	uint8_t		loguuid[16];
+} PACKED;
+
+#define JFS_SUPERBLOCK_OFFSET			0x8000
+
+int volume_id_probe_jfs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct jfs_super_block *js;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	js = (struct jfs_super_block *) volume_id_get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200);
+	if (js == NULL)
+		return -1;
+
+	if (memcmp((char *)js->magic, "JFS1", 4) != 0)
+		return -1;
+
+	volume_id_set_label_raw(id, js->label, 16);
+	volume_id_set_label_string(id, js->label, 16);
+	volume_id_set_uuid(id, js->uuid, 0, UUID_DCE);
+
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "jfs";
+
+	return 0;
+}

=== added file 'libvolume_id/jmicron_raid.c'
--- grub-0.97.orig/libvolume_id/jmicron_raid.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/jmicron_raid.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,57 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct jmicron_meta {
+	int8_t		signature[2];
+	uint8_t		minor_version;
+	uint8_t		major_version;
+	uint16_t	checksum;
+} PACKED;
+
+int volume_id_probe_jmicron_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	uint64_t meta_off;
+	struct jmicron_meta *jm;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	if (size < 0x10000)
+		return -1;
+
+	meta_off = ((size / 0x200)-1) * 0x200;
+	buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	jm = (struct jmicron_meta *) buf;
+	if (memcmp((char *)jm->signature, "JM", 2) != 0)
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	sprintf(id->type_version, "%u.%u", jm->major_version, jm->minor_version);
+	id->type = "jmicron_raid_member";
+
+	return 0;
+}

=== added file 'libvolume_id/linux_raid.c'
--- grub-0.97.orig/libvolume_id/linux_raid.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/linux_raid.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,160 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+static struct mdp0_super_block {
+	uint32_t	md_magic;
+	uint32_t	major_version;
+	uint32_t	minor_version;
+	uint32_t	patch_version;
+	uint32_t	gvalid_words;
+	uint32_t	set_uuid0;
+	uint32_t	ctime;
+	uint32_t	level;
+	uint32_t	size;
+	uint32_t	nr_disks;
+	uint32_t	raid_disks;
+	uint32_t	md_minor;
+	uint32_t	not_persistent;
+	uint32_t	set_uuid1;
+	uint32_t	set_uuid2;
+	uint32_t	set_uuid3;
+} PACKED *mdp0;
+
+struct mdp1_super_block {
+	uint32_t	magic;
+	uint32_t	major_version;
+	uint32_t	feature_map;
+	uint32_t	pad0;
+	uint8_t		set_uuid[16];
+	uint8_t		set_name[32];
+} PACKED *mdp1;
+
+#define MD_RESERVED_BYTES		0x10000
+#define MD_SB_MAGIC			0xa92b4efc
+
+static int volume_id_probe_linux_raid0(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	union {
+		uint32_t ints[4];
+		uint8_t bytes[16];
+	} uuid;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+	if (size < 0x10000)
+		return -1;
+
+	buf = volume_id_get_buffer(id, off, 0x800);
+	if (buf == NULL)
+		return -1;
+	mdp0 = (struct mdp0_super_block *) buf;
+
+	if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
+		uuid.ints[0] = bswap_32(mdp0->set_uuid0);
+		if (le32_to_cpu(mdp0->minor_version >= 90)) {
+			uuid.ints[1] = bswap_32(mdp0->set_uuid1);
+			uuid.ints[2] = bswap_32(mdp0->set_uuid2);
+			uuid.ints[3] = bswap_32(mdp0->set_uuid3);
+		} else {
+			uuid.ints[1] = 0;
+			uuid.ints[2] = 0;
+			uuid.ints[3] = 0;
+		}
+		volume_id_set_uuid(id, uuid.bytes, 0, UUID_FOURINT);
+		sprintf(id->type_version, "%u.%u.%u",
+			 le32_to_cpu(mdp0->major_version),
+			 le32_to_cpu(mdp0->minor_version),
+			 le32_to_cpu(mdp0->patch_version));
+	} else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
+		uuid.ints[0] = mdp0->set_uuid0;
+		if (be32_to_cpu(mdp0->minor_version >= 90)) {
+			uuid.ints[1] = mdp0->set_uuid1;
+			uuid.ints[2] = mdp0->set_uuid2;
+			uuid.ints[3] = mdp0->set_uuid3;
+		} else {
+			uuid.ints[1] = 0;
+			uuid.ints[2] = 0;
+			uuid.ints[3] = 0;
+		}
+		volume_id_set_uuid(id, uuid.bytes, 0, UUID_FOURINT);
+		sprintf(id->type_version, "%u.%u.%u",
+			 be32_to_cpu(mdp0->major_version),
+			 be32_to_cpu(mdp0->minor_version),
+			 be32_to_cpu(mdp0->patch_version));
+	} else
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	id->type = "linux_raid_member";
+	return 0;
+}
+
+static int volume_id_probe_linux_raid1(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	buf = volume_id_get_buffer(id, off, 0x800);
+	if (buf == NULL)
+		return -1;
+	mdp1 = (struct mdp1_super_block *) buf;
+
+	if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
+		return -1;
+
+	volume_id_set_uuid(id, mdp1->set_uuid, 0, UUID_FOURINT);
+	volume_id_set_label_raw(id, mdp1->set_name, 32);
+	volume_id_set_label_string(id, mdp1->set_name, 32);
+	sprintf(id->type_version, "%u", le32_to_cpu(mdp1->major_version));
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	id->type = "linux_raid_member";
+	return 0;
+}
+
+int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	uint64_t sboff;
+
+	/* version 0 at the end of the device */
+	sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
+	if (volume_id_probe_linux_raid0(id, off + sboff, size) == 0)
+		return 0;
+
+	/* version 1.0 at the end of the device */
+	sboff = (size & ~(0x1000 - 1)) - 0x2000;
+	if (volume_id_probe_linux_raid1(id, off + sboff, size) == 0)
+		return 0;
+
+	/* version 1.1 at the start of the device */
+	if (volume_id_probe_linux_raid1(id, off, size) == 0)
+		return 0;
+
+	/* version 1.2 at 4k offset from the start */
+	if (volume_id_probe_linux_raid1(id, off + 0x1000, size) == 0)
+		return 0;
+
+	return -1;
+}

=== added file 'libvolume_id/linux_swap.c'
--- grub-0.97.orig/libvolume_id/linux_swap.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/linux_swap.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,85 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct swap_header_v1_2 {
+	uint8_t		bootbits[1024];
+	uint32_t	version;
+	uint32_t	last_page;
+	uint32_t	nr_badpages;
+	uint8_t		uuid[16];
+	uint8_t		volume_name[16];
+} PACKED;
+
+#define LARGEST_PAGESIZE			0x4000
+
+int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	unsigned int page;
+	struct swap_header_v1_2 *sw;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	/* eek, the swap signature is at the end of the PAGE_SIZE */
+	for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
+			buf = volume_id_get_buffer(id, off + page-10, 10);
+			if (buf == NULL)
+				return -1;
+
+			if (memcmp((char *)buf, "SWAP-SPACE", 10) == 0) {
+				strcpy(id->type_version, "1");
+				goto found;
+			}
+
+			if (memcmp((char *)buf, "SWAPSPACE2", 10) == 0) {
+				id->type = "swap";
+				strcpy(id->type_version, "2");
+				goto found_label;
+			}
+
+			if (memcmp((char *)buf, "S1SUSPEND", 9) == 0) {
+				id->type = "suspend";
+				strcpy(id->type_version, "s1suspend");
+				goto found_label;
+			}
+
+			if (memcmp((char *)buf, "ULSUSPEND", 9) == 0) {
+				id->type = "suspend";
+				strcpy(id->type_version, "ulsuspend");
+				goto found_label;
+			}
+	}
+	return -1;
+
+found_label:
+	sw = (struct swap_header_v1_2 *) volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2));
+	if (sw != NULL) {
+		volume_id_set_label_raw(id, sw->volume_name, 16);
+		volume_id_set_label_string(id, sw->volume_name, 16);
+		volume_id_set_uuid(id, sw->uuid, 0, UUID_DCE);
+	}
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_OTHER);
+	return 0;
+}

=== added file 'libvolume_id/lsi_raid.c'
--- grub-0.97.orig/libvolume_id/lsi_raid.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/lsi_raid.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,55 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct lsi_meta {
+	uint8_t		sig[6];
+} PACKED;
+
+#define LSI_SIGNATURE		"$XIDE$"
+
+int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	uint64_t meta_off;
+	struct lsi_meta *lsi;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	if (size < 0x10000)
+		return -1;
+
+	meta_off = ((size / 0x200)-1) * 0x200;
+	buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	lsi = (struct lsi_meta *) buf;
+	if (memcmp((char *)lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0)
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	id->type = "lsi_mega_raid_member";
+
+	return 0;
+}

=== added file 'libvolume_id/luks.c'
--- grub-0.97.orig/libvolume_id/luks.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/luks.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,76 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 W. Michael Petullo <mike@flyn.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+#define LUKS_SECTOR_SHIFT		9
+#define LUKS_SECTOR_SIZE		(1 << LUKS_SECTOR_SHIFT)
+
+#define LUKS_CIPHERNAME_L		32
+#define LUKS_CIPHERMODE_L		32
+#define LUKS_HASHSPEC_L			32
+#define LUKS_DIGESTSIZE			20
+#define LUKS_SALTSIZE			32
+#define LUKS_NUMKEYS			8
+
+#define LUKS_MAGIC_L			6
+#define LUKS_PHDR_SIZE			(sizeof(struct luks_phdr)/LUKS_SECTOR_SIZE+1)
+#define UUID_STRING_L			40
+static const uint8_t LUKS_MAGIC[] = {'L','U','K','S', 0xba, 0xbe};
+
+struct luks_phdr {
+	uint8_t		magic[LUKS_MAGIC_L];
+	uint16_t	version;
+	uint8_t		cipherName[LUKS_CIPHERNAME_L];
+	uint8_t		cipherMode[LUKS_CIPHERMODE_L];
+	uint8_t		hashSpec[LUKS_HASHSPEC_L];
+	uint32_t	payloadOffset;
+	uint32_t	keyBytes;
+	uint8_t		mkDigest[LUKS_DIGESTSIZE];
+	uint8_t		mkDigestSalt[LUKS_SALTSIZE];
+	uint32_t	mkDigestIterations;
+	uint8_t		uuid[UUID_STRING_L];
+	struct {
+		uint32_t	active;
+		uint32_t	passwordIterations;
+		uint8_t		passwordSalt[LUKS_SALTSIZE];
+		uint32_t	keyMaterialOffset;
+		uint32_t	stripes;
+	} keyblock[LUKS_NUMKEYS];
+};
+
+int volume_id_probe_luks(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct luks_phdr *header;
+
+	header = (struct luks_phdr*) volume_id_get_buffer(id, off, LUKS_PHDR_SIZE);
+	if (header == NULL)
+		return -1;
+
+	if (memcmp((char *)header->magic, (char *)LUKS_MAGIC, LUKS_MAGIC_L))
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_CRYPTO);
+	volume_id_set_uuid(id, header->uuid, 36, UUID_HEX_STRING);
+	sprintf(id->type_version, "%u", le16_to_cpu(header->version));
+	id->type = "crypto_LUKS";
+	return 0;
+}

=== added file 'libvolume_id/lvm.c'
--- grub-0.97.orig/libvolume_id/lvm.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/lvm.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,92 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct lvm1_super_block {
+	uint8_t	id[2];
+} PACKED;
+
+struct lvm2_super_block {
+	uint8_t		id[8];
+	uint64_t	sector_xl;
+	uint32_t	crc_xl;
+	uint32_t	offset_xl;
+	uint8_t		type[8];
+} PACKED;
+
+#define LVM1_SB_OFF			0x400
+#define LVM1_MAGIC			"HM"
+
+int volume_id_probe_lvm1(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	struct lvm1_super_block *lvm;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	buf = volume_id_get_buffer(id, off + LVM1_SB_OFF, 0x800);
+	if (buf == NULL)
+		return -1;
+
+	lvm = (struct lvm1_super_block *) buf;
+
+	if (memcmp((char *)lvm->id, LVM1_MAGIC, 2) != 0)
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	id->type = "LVM1_member";
+
+	return 0;
+}
+
+#define LVM2_LABEL_ID			"LABELONE"
+#define LVM2LABEL_SCAN_SECTORS		4
+
+int volume_id_probe_lvm2(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	unsigned int soff;
+	struct lvm2_super_block *lvm;
+
+	dbg("probing at offset 0x%llx", (unsigned long long) off);
+
+	buf = volume_id_get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200);
+	if (buf == NULL)
+		return -1;
+
+
+	for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) {
+		lvm = (struct lvm2_super_block *) &buf[soff];
+
+		if (memcmp((char *)lvm->id, LVM2_LABEL_ID, 8) == 0)
+			goto found;
+	}
+
+	return -1;
+
+found:
+	memcpy(id->type_version, lvm->type, 8);
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	id->type = "LVM2_member";
+
+	return 0;
+}

=== added file 'libvolume_id/minix.c'
--- grub-0.97.orig/libvolume_id/minix.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/minix.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,112 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+#define MINIX_SUPERBLOCK_OFFSET			0x400
+
+#define MINIX_SUPER_MAGIC			0x137F
+#define MINIX_SUPER_MAGIC2			0x138F
+#define MINIX2_SUPER_MAGIC			0x2468
+#define MINIX2_SUPER_MAGIC2			0x2478
+#define MINIX3_SUPER_MAGIC			0x4d5a
+
+struct minix_super_block
+{
+	uint16_t	s_ninodes;
+	uint16_t	s_nzones;
+	uint16_t	s_imap_blocks;
+	uint16_t	s_zmap_blocks;
+	uint16_t	s_firstdatazone;
+	uint16_t	s_log_zone_size;
+	uint32_t	s_max_size;
+	uint16_t	s_magic;
+	uint16_t	s_state;
+	uint32_t	s_zones;
+} PACKED;
+
+struct minix3_super_block {
+	uint32_t	s_ninodes;
+	uint16_t	s_pad0;
+	uint16_t	s_imap_blocks;
+	uint16_t	s_zmap_blocks;
+	uint16_t	s_firstdatazone;
+	uint16_t	s_log_zone_size;
+	uint16_t	s_pad1;
+	uint32_t	s_max_size;
+	uint32_t	s_zones;
+	uint16_t	s_magic;
+	uint16_t	s_pad2;
+	uint16_t	s_blocksize;
+	uint8_t 	s_disk_version;
+} PACKED;
+
+int volume_id_probe_minix(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	uint8_t *buf;
+	struct minix_super_block *ms;
+	struct minix3_super_block *m3s;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	buf = volume_id_get_buffer(id, off + MINIX_SUPERBLOCK_OFFSET, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	ms = (struct minix_super_block *) buf;
+
+	if (ms->s_magic == MINIX_SUPER_MAGIC ||
+	    ms->s_magic == bswap_16(MINIX_SUPER_MAGIC)) {
+		strcpy(id->type_version, "1");
+		goto found;
+	}
+	if (ms->s_magic == MINIX_SUPER_MAGIC2 ||
+	    ms->s_magic == bswap_16(MINIX_SUPER_MAGIC2)) {
+		strcpy(id->type_version, "1");
+		goto found;
+	}
+	if (ms->s_magic == MINIX2_SUPER_MAGIC ||
+	    ms->s_magic == bswap_16(MINIX2_SUPER_MAGIC)) {
+		strcpy(id->type_version, "2");
+		goto found;
+	}
+	if (ms->s_magic == MINIX2_SUPER_MAGIC2 ||
+	    ms->s_magic == bswap_16(MINIX2_SUPER_MAGIC2)) {
+		strcpy(id->type_version, "2");
+		goto found;
+	}
+
+	m3s = (struct minix3_super_block *) buf;
+	if (m3s->s_magic == MINIX3_SUPER_MAGIC ||
+	    m3s->s_magic == bswap_16(MINIX3_SUPER_MAGIC)) {
+		strcpy(id->type_version, "3");
+		goto found;
+	}
+	goto exit;
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "minix";
+	return 0;
+
+exit:
+	return -1;
+}

=== added file 'libvolume_id/misc.c'
--- grub-0.97.orig/libvolume_id/misc.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/misc.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,35 @@
+/*
+ * volume_id/misc.c
+ *
+ * Copyright (C) 2008 Canonical Ltd.
+ *
+ *      This program is free software; you can redistribute it and/or modify it
+ *      under the terms of the GNU General Public License as published by the
+ *      Free Software Foundation version 2 of the License.
+ */
+#define _GNU_SOURCE
+#include <string.h>
+#undef strchr
+
+/*
+ *  Misc auxiliary functions required for volume_id inside grub
+ */
+size_t strnlen(const char *s, size_t limit)
+{
+	size_t length = 0;
+	while ( (length < limit) && (*s++) ) 
+		length++;
+
+   	return length;
+}
+
+char *strchr (const char *s, int c)
+{
+	do {
+		if ( *s == c ) {
+			return (char*)s;
+      		}
+  	} while ( *s++ );
+
+  	return 0;
+}

=== added file 'libvolume_id/netware.c'
--- grub-0.97.orig/libvolume_id/netware.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/netware.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,98 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+#define NW_SUPERBLOCK_OFFSET			0x1000
+
+struct netware_super_block {
+	uint8_t		SBH_Signature[4];
+	uint16_t	SBH_VersionMajor;
+	uint16_t	SBH_VersionMinor;
+	uint16_t	SBH_VersionMediaMajor;
+	uint16_t	SBH_VersionMediaMinor;
+	uint32_t	SBH_ItemsMoved;
+	uint8_t		SBH_InternalID[16];
+	uint32_t	SBH_PackedSize;
+	uint32_t	SBH_Checksum;
+	uint32_t	supersyncid;
+	int64_t		superlocation[4];
+	uint32_t	physSizeUsed;
+	uint32_t	sizeUsed;
+	uint32_t	superTimeStamp;
+	uint32_t	reserved0[1];
+	int64_t		SBH_LoggedPoolDataBlk;
+	int64_t		SBH_PoolDataBlk;
+	uint8_t		SBH_OldInternalID[16];
+	uint32_t	SBH_PoolToLVStartUTC;
+	uint32_t	SBH_PoolToLVEndUTC;
+	uint16_t	SBH_VersionMediaMajorCreate;
+	uint16_t	SBH_VersionMediaMinorCreate;
+	uint32_t	SBH_BlocksMoved;
+	uint32_t	SBH_TempBTSpBlk;
+	uint32_t	SBH_TempFTSpBlk;
+	uint32_t	SBH_TempFTSpBlk1;
+	uint32_t	SBH_TempFTSpBlk2;
+	uint32_t 	nssMagicNumber;
+	uint32_t	poolClassID;
+	uint32_t 	poolID;
+	uint32_t	createTime;
+	int64_t		SBH_LoggedVolumeDataBlk;
+	int64_t		SBH_VolumeDataBlk;
+	int64_t		SBH_SystemBeastBlkNum;
+	uint64_t	totalblocks;
+	uint16_t 	SBH_Name[64];
+	uint8_t		SBH_VolumeID[16];
+	uint8_t		SBH_PoolID[16];
+	uint8_t		SBH_PoolInternalID[16];
+	uint64_t	SBH_Lsn;
+	uint32_t	SBH_SS_Enabled;
+	uint32_t	SBH_SS_CreateTime;
+	uint8_t		SBH_SS_OriginalPoolID[16];
+	uint8_t		SBH_SS_OriginalVolumeID[16];
+	uint8_t		SBH_SS_Guid[16];
+	uint16_t	SBH_SS_OriginalName[64];
+	uint32_t	reserved2[64-(2+46)];
+} PACKED;
+
+int volume_id_probe_netware(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct netware_super_block *nw;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	nw = (struct netware_super_block *) volume_id_get_buffer(id, off + NW_SUPERBLOCK_OFFSET, 0x200);
+	if (nw == NULL)
+		return -1;
+
+	if (memcmp((char *)nw->SBH_Signature, "SPB5", 4) != 0)
+		return -1;
+
+	volume_id_set_uuid(id, nw->SBH_PoolID, 0, UUID_DCE);
+
+	sprintf(id->type_version, "%u.%02u",
+		 le16_to_cpu(nw->SBH_VersionMediaMajor), le16_to_cpu(nw->SBH_VersionMediaMinor));
+
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "nss";
+
+	return 0;
+}

=== added file 'libvolume_id/ntfs.c'
--- grub-0.97.orig/libvolume_id/ntfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/ntfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,192 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+static struct ntfs_super_block {
+	uint8_t		jump[3];
+	uint8_t		oem_id[8];
+	uint16_t	bytes_per_sector;
+	uint8_t		sectors_per_cluster;
+	uint16_t	reserved_sectors;
+	uint8_t		fats;
+	uint16_t	root_entries;
+	uint16_t	sectors;
+	uint8_t		media_type;
+	uint16_t	sectors_per_fat;
+	uint16_t	sectors_per_track;
+	uint16_t	heads;
+	uint32_t	hidden_sectors;
+	uint32_t	large_sectors;
+	uint16_t	unused[2];
+	uint64_t	number_of_sectors;
+	uint64_t	mft_cluster_location;
+	uint64_t	mft_mirror_cluster_location;
+	int8_t		cluster_per_mft_record;
+	uint8_t		reserved1[3];
+	int8_t		cluster_per_index_record;
+	uint8_t		reserved2[3];
+	uint8_t		volume_serial[8];
+	uint16_t	checksum;
+} PACKED *ns;
+
+static struct master_file_table_record {
+	uint8_t		magic[4];
+	uint16_t	usa_ofs;
+	uint16_t	usa_count;
+	uint64_t	lsn;
+	uint16_t	sequence_number;
+	uint16_t	link_count;
+	uint16_t	attrs_offset;
+	uint16_t	flags;
+	uint32_t	bytes_in_use;
+	uint32_t	bytes_allocated;
+} PACKED *mftr;
+
+static struct file_attribute {
+	uint32_t	type;
+	uint32_t	len;
+	uint8_t		non_resident;
+	uint8_t		name_len;
+	uint16_t	name_offset;
+	uint16_t	flags;
+	uint16_t	instance;
+	uint32_t	value_len;
+	uint16_t	value_offset;
+} PACKED *attr;
+
+static struct volume_info {
+	uint64_t	reserved;
+	uint8_t		major_ver;
+	uint8_t		minor_ver;
+} PACKED *info;
+
+#define MFT_RECORD_VOLUME			3
+#define MFT_RECORD_ATTR_VOLUME_NAME		0x60
+#define MFT_RECORD_ATTR_VOLUME_INFO		0x70
+#define MFT_RECORD_ATTR_OBJECT_ID		0x40
+#define MFT_RECORD_ATTR_END			0xffffffffu
+
+#undef debug
+#define debug grub_printf
+
+int volume_id_probe_ntfs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	unsigned int sector_size;
+	unsigned int cluster_size;
+	uint64_t mft_cluster;
+	uint64_t mft_off;
+	unsigned int mft_record_size;
+	unsigned int attr_type;
+	unsigned int attr_off;
+	unsigned int attr_len;
+	unsigned int val_off;
+	unsigned int val_len;
+	const uint8_t *buf;
+	const uint8_t *val;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	ns = (struct ntfs_super_block *) volume_id_get_buffer(id, off, 0x200);
+	if (ns == NULL)
+		return -1;
+
+	if (memcmp((char *)ns->oem_id, "NTFS", 4) != 0)
+		return -1;
+
+	volume_id_set_uuid(id, ns->volume_serial, 0, UUID_64BIT_LE);
+
+	sector_size = le16_to_cpu(ns->bytes_per_sector);
+	if (sector_size < 0x200)
+		return -1;
+
+	cluster_size = ns->sectors_per_cluster * sector_size;
+	mft_cluster = le64_to_cpu(ns->mft_cluster_location);
+	mft_off = mft_cluster * cluster_size;
+
+	if (ns->cluster_per_mft_record < 0)
+		/* size = -log2(mft_record_size); normally 1024 Bytes */
+		mft_record_size = 1 << -ns->cluster_per_mft_record;
+	else
+		mft_record_size = ns->cluster_per_mft_record * cluster_size;
+
+	dbg("sectorsize  0x%x", sector_size);
+	dbg("clustersize 0x%x", cluster_size);
+	dbg("mftcluster  %llu", (unsigned long long) mft_cluster);
+	dbg("mftoffset  0x%llx", (unsigned long long) mft_off);
+	dbg("cluster per mft_record  %i", ns->cluster_per_mft_record);
+	dbg("mft record size  %i", mft_record_size);
+
+	buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
+			 mft_record_size);
+	if (buf == NULL)
+		return -1;
+
+	mftr = (struct master_file_table_record*) buf;
+	dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
+	if (memcmp((char *)mftr->magic, "FILE", 4) != 0)
+		return -1;
+
+	attr_off = le16_to_cpu(mftr->attrs_offset);
+	dbg("file $Volume's attributes are at offset %i", attr_off);
+
+	while (1) {
+		attr = (struct file_attribute*) &buf[attr_off];
+		attr_type = le32_to_cpu(attr->type);
+		attr_len = le16_to_cpu(attr->len);
+		val_off = le16_to_cpu(attr->value_offset);
+		val_len = le32_to_cpu(attr->value_len);
+		attr_off += attr_len;
+
+		if (attr_len == 0)
+			break;
+
+		if (attr_off >= mft_record_size)
+			break;
+
+		if (attr_type == MFT_RECORD_ATTR_END)
+			break;
+
+		dbg("found attribute type 0x%x, len %i, at offset %i",
+		    attr_type, attr_len, attr_off);
+
+		if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
+			dbg("found info, len %i", val_len);
+			info = (struct volume_info*) (((uint8_t *) attr) + val_off);
+			sprintf(id->type_version, "%u.%u", info->major_ver, info->minor_ver);
+		}
+
+		if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
+			dbg("found label, len %i", val_len);
+			if (val_len > VOLUME_ID_LABEL_SIZE)
+				val_len = VOLUME_ID_LABEL_SIZE;
+
+			val = ((uint8_t *) attr) + val_off;
+			volume_id_set_label_raw(id, val, val_len);
+			volume_id_set_label_unicode16(id, val, LE, val_len);
+		}
+	}
+
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "ntfs";
+
+	return 0;
+}

=== added file 'libvolume_id/nvidia_raid.c'
--- grub-0.97.orig/libvolume_id/nvidia_raid.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/nvidia_raid.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,59 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct nvidia_meta {
+	uint8_t		vendor[8];
+	uint32_t	size;
+	uint32_t	chksum;
+	uint16_t	version;
+} PACKED;
+
+#define NVIDIA_SIGNATURE		"NVIDIA"
+
+int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	uint64_t meta_off;
+	struct nvidia_meta *nv;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	if (size < 0x10000)
+		return -1;
+
+	meta_off = ((size / 0x200)-2) * 0x200;
+	buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	nv = (struct nvidia_meta *) buf;
+	if (memcmp((char *)nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0)
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	sprintf(id->type_version, "%u", le16_to_cpu(nv->version));
+	id->type = "nvidia_raid_member";
+
+	return 0;
+}

=== added file 'libvolume_id/ocfs.c'
--- grub-0.97.orig/libvolume_id/ocfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/ocfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,186 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Andre Masella <andre@masella.no-ip.org>
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct ocfs1_super_block_header {
+	uint32_t	minor_version;
+	uint32_t	major_version;
+	uint8_t		signature[128];
+	uint8_t		mount_point[128];
+	uint64_t	serial_num;
+	uint64_t	device_size;
+	uint64_t	start_off;
+	uint64_t	bitmap_off;
+	uint64_t	publ_off;
+	uint64_t	vote_off;
+	uint64_t	root_bitmap_off;
+	uint64_t	data_start_off;
+	uint64_t	root_bitmap_size;
+	uint64_t	root_off;
+	uint64_t	root_size;
+	uint64_t	cluster_size;
+	uint64_t	num_nodes;
+	uint64_t	num_clusters;
+	uint64_t	dir_node_size;
+	uint64_t	file_node_size;
+	uint64_t	internal_off;
+	uint64_t	node_cfg_off;
+	uint64_t	node_cfg_size;
+	uint64_t	new_cfg_off;
+	uint32_t	prot_bits;
+	int32_t		excl_mount;
+} PACKED;
+
+struct ocfs1_super_block_label {
+	struct ocfs1_disk_lock {
+		uint32_t	curr_master;
+		uint8_t		file_lock;
+		uint8_t		compat_pad[3];
+		uint64_t	last_write_time;
+		uint64_t	last_read_time;
+		uint32_t	writer_node_num;
+		uint32_t	reader_node_num;
+		uint64_t	oin_node_map;
+		uint64_t	dlock_seq_num;
+	} PACKED disk_lock;
+	uint8_t		label[64];
+	uint16_t	label_len;
+	uint8_t		vol_id[16];
+	uint16_t	vol_id_len;
+	uint8_t		cluster_name[64];
+	uint16_t	cluster_name_len;
+} PACKED;
+
+struct ocfs2_super_block {
+	uint8_t		i_signature[8];
+	uint32_t	i_generation;
+	int16_t		i_suballoc_slot;
+	uint16_t	i_suballoc_bit;
+	uint32_t	i_reserved0;
+	uint32_t	i_clusters;
+	uint32_t	i_uid;
+	uint32_t	i_gid;
+	uint64_t	i_size;
+	uint16_t	i_mode;
+	uint16_t	i_links_count;
+	uint32_t	i_flags;
+	uint64_t	i_atime;
+	uint64_t	i_ctime;
+	uint64_t	i_mtime;
+	uint64_t	i_dtime;
+	uint64_t	i_blkno;
+	uint64_t	i_last_eb_blk;
+	uint32_t	i_fs_generation;
+	uint32_t	i_atime_nsec;
+	uint32_t	i_ctime_nsec;
+	uint32_t	i_mtime_nsec;
+	uint64_t	i_reserved1[9];
+	uint64_t	i_pad1;
+	uint16_t	s_major_rev_level;
+	uint16_t	s_minor_rev_level;
+	uint16_t	s_mnt_count;
+	int16_t		s_max_mnt_count;
+	uint16_t	s_state;
+	uint16_t	s_errors;
+	uint32_t	s_checkinterval;
+	uint64_t	s_lastcheck;
+	uint32_t	s_creator_os;
+	uint32_t	s_feature_compat;
+	uint32_t	s_feature_incompat;
+	uint32_t	s_feature_ro_compat;
+	uint64_t	s_root_blkno;
+	uint64_t	s_system_dir_blkno;
+	uint32_t	s_blocksize_bits;
+	uint32_t	s_clustersize_bits;
+	uint16_t	s_max_slots;
+	uint16_t	s_reserved1;
+	uint32_t	s_reserved2;
+	uint64_t	s_first_cluster_group;
+	uint8_t		s_label[64];
+	uint8_t		s_uuid[16];
+} PACKED;
+
+int volume_id_probe_ocfs1(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	struct ocfs1_super_block_header *osh;
+	struct ocfs1_super_block_label *osl;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	buf = volume_id_get_buffer(id, off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	osh = (struct ocfs1_super_block_header *) buf;
+	if (memcmp((char *)osh->signature, "OracleCFS", 9) != 0)
+		return -1;
+	sprintf(id->type_version, "%u.%u", osh->major_version, osh->minor_version);
+
+	dbg("found OracleCFS signature, now reading label");
+	buf = volume_id_get_buffer(id, off + 0x200, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	osl = (struct ocfs1_super_block_label *) buf;
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	if (osl->label_len <= 64) {
+		volume_id_set_label_raw(id, osl->label, 64);
+		volume_id_set_label_string(id, osl->label, 64);
+	}
+	if (osl->vol_id_len == 16)
+		volume_id_set_uuid(id, osl->vol_id, 0, UUID_DCE);
+	id->type = "ocfs";
+	return 0;
+}
+
+#define OCFS2_MAX_BLOCKSIZE		0x1000
+#define OCFS2_SUPER_BLOCK_BLKNO		2
+
+int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	struct ocfs2_super_block *os;
+	size_t blksize;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	for (blksize = 0x200; blksize <= OCFS2_MAX_BLOCKSIZE; blksize <<= 1) {
+		buf = volume_id_get_buffer(id, off + OCFS2_SUPER_BLOCK_BLKNO * blksize, 0x200);
+		if (buf == NULL)
+			return -1;
+
+		os = (struct ocfs2_super_block *) buf;
+		if (memcmp((char *)os->i_signature, "OCFSV2", 6) != 0)
+			continue;
+
+		volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+		volume_id_set_label_raw(id, os->s_label, 64);
+		volume_id_set_label_string(id, os->s_label, 64);
+		volume_id_set_uuid(id, os->s_uuid, 0, UUID_DCE);
+		sprintf(id->type_version, "%u.%u", os->s_major_rev_level, os->s_minor_rev_level);
+		id->type = "ocfs2";
+		return 0;
+	}
+	return -1;
+}

=== added file 'libvolume_id/promise_raid.c'
--- grub-0.97.orig/libvolume_id/promise_raid.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/promise_raid.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,65 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct promise_meta {
+	uint8_t	sig[24];
+} PACKED;
+
+#define PDC_CONFIG_OFF		0x1200
+#define PDC_SIGNATURE		"Promise Technology, Inc."
+
+int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	struct promise_meta *pdc;
+	unsigned int i;
+	static unsigned int sectors[] = {
+		63, 255, 256, 16, 399, 0
+	};
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	if (size < 0x40000)
+		return -1;
+
+	for (i = 0; sectors[i] != 0; i++) {
+		uint64_t meta_off;
+
+		meta_off = ((size / 0x200) - sectors[i]) * 0x200;
+		buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+		if (buf == NULL)
+			return -1;
+
+		pdc = (struct promise_meta *) buf;
+		if (memcmp((char *)pdc->sig, PDC_SIGNATURE, sizeof(PDC_SIGNATURE)-1) == 0)
+			goto found;
+	}
+	return -1;
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	id->type = "promise_fasttrack_raid_member";
+
+	return 0;
+}

=== added file 'libvolume_id/reiserfs.c'
--- grub-0.97.orig/libvolume_id/reiserfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/reiserfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,113 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2005 Tobias Klauser <tklauser@access.unizh.ch>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct reiserfs_super_block {
+	uint32_t	blocks_count;
+	uint32_t	free_blocks;
+	uint32_t	root_block;
+	uint32_t	journal_block;
+	uint32_t	journal_dev;
+	uint32_t	orig_journal_size;
+	uint32_t	dummy2[5];
+	uint16_t	blocksize;
+	uint16_t	dummy3[3];
+	uint8_t		magic[12];
+	uint32_t	dummy4[5];
+	uint8_t		uuid[16];
+	uint8_t		label[16];
+} PACKED;
+
+struct reiser4_super_block {
+	uint8_t		magic[16];
+	uint16_t	dummy[2];
+	uint8_t		uuid[16];
+	uint8_t		label[16];
+	uint64_t	dummy2;
+} PACKED;
+
+#define REISERFS1_SUPERBLOCK_OFFSET		0x2000
+#define REISERFS_SUPERBLOCK_OFFSET		0x10000
+
+int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct reiserfs_super_block *rs;
+	struct reiser4_super_block *rs4;
+	uint8_t	 *buf;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	buf = volume_id_get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	rs = (struct reiserfs_super_block *) buf;
+	if (memcmp((char *)rs->magic, "ReIsErFs", 8) == 0) {
+		strcpy(id->type_version, "3.5");
+		id->type = "reiserfs";
+		goto found;
+	}
+	if (memcmp((char *)rs->magic, "ReIsEr2Fs", 9) == 0) {
+		strcpy(id->type_version, "3.6");
+		id->type = "reiserfs";
+		goto found_label;
+	}
+	if (memcmp((char *)rs->magic, "ReIsEr3Fs", 9) == 0) {
+		strcpy(id->type_version, "JR");
+		id->type = "reiserfs";
+		goto found_label;
+	}
+
+	rs4 = (struct reiser4_super_block *) buf;
+	if (memcmp((char *)rs4->magic, "ReIsEr4", 7) == 0) {
+		strcpy(id->type_version, "4");
+		volume_id_set_label_raw(id, rs4->label, 16);
+		volume_id_set_label_string(id, rs4->label, 16);
+		volume_id_set_uuid(id, rs4->uuid, 0, UUID_DCE);
+		id->type = "reiser4";
+		goto found;
+	}
+
+	buf = volume_id_get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	rs = (struct reiserfs_super_block *) buf;
+	if (memcmp((char *)rs->magic, "ReIsErFs", 8) == 0) {
+		strcpy(id->type_version, "3.5");
+		id->type = "reiserfs";
+		goto found;
+	}
+
+	return -1;
+
+found_label:
+	volume_id_set_label_raw(id, rs->label, 16);
+	volume_id_set_label_string(id, rs->label, 16);
+	volume_id_set_uuid(id, rs->uuid, 0, UUID_DCE);
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+
+	return 0;
+}

=== added file 'libvolume_id/romfs.c'
--- grub-0.97.orig/libvolume_id/romfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/romfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,55 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct romfs_super {
+	uint8_t magic[8];
+	uint32_t size;
+	uint32_t checksum;
+	uint8_t name[0];
+} PACKED;
+
+int volume_id_probe_romfs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct romfs_super *rfs;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	rfs = (struct romfs_super *) volume_id_get_buffer(id, off, 0x200);
+	if (rfs == NULL)
+		return -1;
+
+	if (memcmp((char *)rfs->magic, "-rom1fs-", 4) == 0) {
+		size_t len = strlen((char *)rfs->name);
+
+		if (len) {
+			volume_id_set_label_raw(id, rfs->name, len);
+			volume_id_set_label_string(id, rfs->name, len);
+		}
+
+		volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+		id->type = "romfs";
+		return 0;
+	}
+
+	return -1;
+}

=== added file 'libvolume_id/silicon_raid.c'
--- grub-0.97.orig/libvolume_id/silicon_raid.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/silicon_raid.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,71 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct silicon_meta {
+	uint8_t		unknown0[0x2E];
+	uint8_t		ascii_version[0x36 - 0x2E];
+	uint8_t		diskname[0x56 - 0x36];
+	uint8_t		unknown1[0x60 - 0x56];
+	uint32_t	magic;
+	uint32_t	unknown1a[0x6C - 0x64];
+	uint32_t	array_sectors_low;
+	uint32_t	array_sectors_high;
+	uint8_t		unknown2[0x78 - 0x74];
+	uint32_t	thisdisk_sectors;
+	uint8_t		unknown3[0x100 - 0x7C];
+	uint8_t		unknown4[0x104 - 0x100];
+	uint16_t	product_id;
+	uint16_t	vendor_id;
+	uint16_t	minor_ver;
+	uint16_t	major_ver;
+} PACKED;
+
+#define SILICON_MAGIC		0x2F000000
+
+int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	uint64_t meta_off;
+	struct silicon_meta *sil;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	if (size < 0x10000)
+		return -1;
+
+	meta_off = ((size / 0x200)-1) * 0x200;
+	buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	sil = (struct silicon_meta *) buf;
+	if (le32_to_cpu(sil->magic) != SILICON_MAGIC)
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	sprintf(id->type_version, "%u.%u", le16_to_cpu(sil->major_ver), le16_to_cpu(sil->minor_ver));
+	id->type = "silicon_medley_raid_member";
+
+	return 0;
+}

=== added file 'libvolume_id/squashfs.c'
--- grub-0.97.orig/libvolume_id/squashfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/squashfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,63 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+#define SQUASHFS_MAGIC		0x73717368
+
+struct squashfs_super {
+	uint32_t	s_magic;
+	uint32_t	inodes;
+	uint32_t	bytes_used_2;
+	uint32_t	uid_start_2;
+	uint32_t	guid_start_2;
+	uint32_t	inode_table_start_2;
+	uint32_t	directory_table_start_2;
+	uint16_t	s_major;
+	uint16_t	s_minor;
+} PACKED;
+
+int volume_id_probe_squashfs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct squashfs_super *sqs;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	sqs = (struct squashfs_super *) volume_id_get_buffer(id, off, 0x200);
+	if (sqs == NULL)
+		return -1;
+
+	if (sqs->s_magic == SQUASHFS_MAGIC) {
+		sprintf(id->type_version, "%u.%u", sqs->s_major, sqs->s_minor);
+		goto found;
+	}
+	if (sqs->s_magic == bswap_32(SQUASHFS_MAGIC)) {
+		sprintf(id->type_version, "%u.%u", bswap_16(sqs->s_major), bswap_16(sqs->s_minor));
+		goto found;
+	}
+
+	return -1;
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "squashfs";
+	return 0;
+}

=== added file 'libvolume_id/strfuncs.h'
--- grub-0.97.orig/libvolume_id/strfuncs.h	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/strfuncs.h	2008-07-15 12:31:43 +0000
@@ -0,0 +1,5 @@
+
+#include <stdlib.h>
+
+size_t strnlen(const char *s, size_t limit);
+char  *strchr (const char *s, int c);

=== added file 'libvolume_id/sysv.c'
--- grub-0.97.orig/libvolume_id/sysv.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/sysv.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,128 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+#define SYSV_NICINOD			100
+#define SYSV_NICFREE			50
+
+struct sysv_super
+{
+	uint16_t	s_isize;
+	uint16_t	s_pad0;
+	uint32_t	s_fsize;
+	uint16_t	s_nfree;
+	uint16_t	s_pad1;
+	uint32_t	s_free[SYSV_NICFREE];
+	uint16_t	s_ninode;
+	uint16_t	s_pad2;
+	uint16_t	s_inode[SYSV_NICINOD];
+	uint8_t		s_flock;
+	uint8_t		s_ilock;
+	uint8_t		s_fmod;
+	uint8_t		s_ronly;
+	uint32_t	s_time;
+	uint16_t	s_dinfo[4];
+	uint32_t	s_tfree;
+	uint16_t	s_tinode;
+	uint16_t	s_pad3;
+	uint8_t		s_fname[6];
+	uint8_t		s_fpack[6];
+	uint32_t	s_fill[12];
+	uint32_t	s_state;
+	uint32_t	s_magic;
+	uint32_t	s_type;
+} PACKED;
+
+#define XENIX_NICINOD				100
+#define XENIX_NICFREE				100
+
+struct xenix_super {
+	uint16_t	s_isize;
+	uint32_t	s_fsize;
+	uint16_t	s_nfree;
+	uint32_t	s_free[XENIX_NICFREE];
+	uint16_t	s_ninode;
+	uint16_t	s_inode[XENIX_NICINOD];
+	uint8_t		s_flock;
+	uint8_t		s_ilock;
+	uint8_t		s_fmod;
+	uint8_t		s_ronly;
+	uint32_t	s_time;
+	uint32_t	s_tfree;
+	uint16_t	s_tinode;
+	uint16_t	s_dinfo[4];
+	uint8_t		s_fname[6];
+	uint8_t		s_fpack[6];
+	uint8_t		s_clean;
+	uint8_t		s_fill[371];
+	uint32_t	s_magic;
+	uint32_t	s_type;
+} PACKED;
+
+#define SYSV_SUPERBLOCK_BLOCK			0x01
+#define SYSV_MAGIC				0xfd187e20
+#define XENIX_SUPERBLOCK_BLOCK			0x18
+#define XENIX_MAGIC				0x2b5544
+#define SYSV_MAX_BLOCKSIZE			0x800
+
+int volume_id_probe_sysv(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct sysv_super *vs;
+	struct xenix_super *xs;
+	unsigned int boff;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) {
+		vs = (struct sysv_super *)
+			volume_id_get_buffer(id, off + (boff * SYSV_SUPERBLOCK_BLOCK), 0x200);
+		if (vs == NULL)
+			return -1;
+
+		if (vs->s_magic == cpu_to_le32(SYSV_MAGIC) || vs->s_magic == cpu_to_be32(SYSV_MAGIC)) {
+			volume_id_set_label_raw(id, vs->s_fname, 6);
+			volume_id_set_label_string(id, vs->s_fname, 6);
+			id->type = "sysv";
+			goto found;
+		}
+	}
+
+	for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) {
+		xs = (struct xenix_super *)
+			volume_id_get_buffer(id, off + (boff + XENIX_SUPERBLOCK_BLOCK), 0x200);
+		if (xs == NULL)
+			return -1;
+
+		if (xs->s_magic == cpu_to_le32(XENIX_MAGIC) || xs->s_magic == cpu_to_be32(XENIX_MAGIC)) {
+			volume_id_set_label_raw(id, xs->s_fname, 6);
+			volume_id_set_label_string(id, xs->s_fname, 6);
+			id->type = "xenix";
+			goto found;
+		}
+	}
+
+	return -1;
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	return 0;
+}

=== added file 'libvolume_id/udf.c'
--- grub-0.97.orig/libvolume_id/udf.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/udf.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,173 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct volume_descriptor {
+	struct descriptor_tag {
+		uint16_t	id;
+		uint16_t	version;
+		uint8_t		checksum;
+		uint8_t		reserved;
+		uint16_t	serial;
+		uint16_t	crc;
+		uint16_t	crc_len;
+		uint32_t	location;
+	} PACKED tag;
+	union {
+		struct anchor_descriptor {
+			uint32_t	length;
+			uint32_t	location;
+		} PACKED anchor;
+		struct primary_descriptor {
+			uint32_t	seq_num;
+			uint32_t	desc_num;
+			struct dstring {
+				uint8_t	clen;
+				uint8_t	c[31];
+			} PACKED ident;
+		} PACKED primary;
+	} PACKED type;
+} PACKED;
+
+struct volume_structure_descriptor {
+	uint8_t		type;
+	uint8_t		id[5];
+	uint8_t		version;
+} PACKED;
+
+#define UDF_VSD_OFFSET			0x8000
+
+int volume_id_probe_udf(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct volume_descriptor *vd;
+	struct volume_structure_descriptor *vsd;
+	unsigned int bs;
+	unsigned int b;
+	unsigned int type;
+	unsigned int count;
+	unsigned int loc;
+	unsigned int clen;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
+	if (vsd == NULL)
+		return -1;
+
+	if (memcmp((char *)vsd->id, "NSR02", 5) == 0)
+		goto blocksize;
+	if (memcmp((char *)vsd->id, "NSR03", 5) == 0)
+		goto blocksize;
+	if (memcmp((char *)vsd->id, "BEA01", 5) == 0)
+		goto blocksize;
+	if (memcmp((char *)vsd->id, "BOOT2", 5) == 0)
+		goto blocksize;
+	if (memcmp((char *)vsd->id, "CD001", 5) == 0)
+		goto blocksize;
+	if (memcmp((char *)vsd->id, "CDW02", 5) == 0)
+		goto blocksize;
+	if (memcmp((char *)vsd->id, "TEA03", 5) == 0)
+		goto blocksize;
+	return -1;
+
+blocksize:
+	/* search the next VSD to get the logical block size of the volume */
+	for (bs = 0x800; bs < 0x8000; bs += 0x800) {
+		vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
+		if (vsd == NULL)
+			return -1;
+		dbg("test for blocksize: 0x%x", bs);
+		if (vsd->id[0] != '\0')
+			goto nsr;
+	}
+	return -1;
+
+nsr:
+	/* search the list of VSDs for a NSR descriptor */
+	for (b = 0; b < 64; b++) {
+		vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
+		if (vsd == NULL)
+			return -1;
+
+		dbg("vsd: %c%c%c%c%c",
+		    vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
+
+		if (vsd->id[0] == '\0')
+			return -1;
+		if (memcmp((char *)vsd->id, "NSR02", 5) == 0)
+			goto anchor;
+		if (memcmp((char *)vsd->id, "NSR03", 5) == 0)
+			goto anchor;
+	}
+	return -1;
+
+anchor:
+	/* read anchor volume descriptor */
+	vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + (256 * bs), 0x200);
+	if (vd == NULL)
+		return -1;
+
+	type = le16_to_cpu(vd->tag.id);
+	if (type != 2) /* TAG_ID_AVDP */
+		goto found;
+
+	/* get desriptor list address and block count */
+	count = le32_to_cpu(vd->type.anchor.length) / bs;
+	loc = le32_to_cpu(vd->type.anchor.location);
+	dbg("0x%x descriptors starting at logical secor 0x%x", count, loc);
+
+	/* pick the primary descriptor from the list */
+	for (b = 0; b < count; b++) {
+		vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + ((loc + b) * bs), 0x200);
+		if (vd == NULL)
+			return -1;
+
+		type = le16_to_cpu(vd->tag.id);
+		dbg("descriptor type %i", type);
+
+		/* check validity */
+		if (type == 0)
+			goto found;
+		if (le32_to_cpu(vd->tag.location) != loc + b)
+			goto found;
+
+		if (type == 1) /* TAG_ID_PVD */
+			goto pvd;
+	}
+	goto found;
+
+pvd:
+	volume_id_set_label_raw(id, &(vd->type.primary.ident.clen), 32);
+
+	clen = vd->type.primary.ident.clen;
+	dbg("label string charsize=%i bit", clen);
+	if (clen == 8)
+		volume_id_set_label_string(id, vd->type.primary.ident.c, 31);
+	else if (clen == 16)
+		volume_id_set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "udf";
+
+	return 0;
+}

=== added file 'libvolume_id/ufs.c'
--- grub-0.97.orig/libvolume_id/ufs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/ufs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,217 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct ufs_super_block {
+	uint32_t	fs_link;
+	uint32_t	fs_rlink;
+	uint32_t	fs_sblkno;
+	uint32_t	fs_cblkno;
+	uint32_t	fs_iblkno;
+	uint32_t	fs_dblkno;
+	uint32_t	fs_cgoffset;
+	uint32_t	fs_cgmask;
+	uint32_t	fs_time;
+	uint32_t	fs_size;
+	uint32_t	fs_dsize;
+	uint32_t	fs_ncg;	
+	uint32_t	fs_bsize;
+	uint32_t	fs_fsize;
+	uint32_t	fs_frag;
+	uint32_t	fs_minfree;
+	uint32_t	fs_rotdelay;
+	uint32_t	fs_rps;	
+	uint32_t	fs_bmask;
+	uint32_t	fs_fmask;
+	uint32_t	fs_bshift;
+	uint32_t	fs_fshift;
+	uint32_t	fs_maxcontig;
+	uint32_t	fs_maxbpg;
+	uint32_t	fs_fragshift;
+	uint32_t	fs_fsbtodb;
+	uint32_t	fs_sbsize;
+	uint32_t	fs_csmask;
+	uint32_t	fs_csshift;
+	uint32_t	fs_nindir;
+	uint32_t	fs_inopb;
+	uint32_t	fs_nspf;
+	uint32_t	fs_optim;
+	uint32_t	fs_npsect_state;
+	uint32_t	fs_interleave;
+	uint32_t	fs_trackskew;
+	uint32_t	fs_id[2];
+	uint32_t	fs_csaddr;
+	uint32_t	fs_cssize;
+	uint32_t	fs_cgsize;
+	uint32_t	fs_ntrak;
+	uint32_t	fs_nsect;
+	uint32_t	fs_spc;	
+	uint32_t	fs_ncyl;
+	uint32_t	fs_cpg;
+	uint32_t	fs_ipg;
+	uint32_t	fs_fpg;
+	struct ufs_csum {
+		uint32_t	cs_ndir;
+		uint32_t	cs_nbfree;
+		uint32_t	cs_nifree;
+		uint32_t	cs_nffree;
+	} PACKED fs_cstotal;
+	int8_t		fs_fmod;
+	int8_t		fs_clean;
+	int8_t		fs_ronly;
+	int8_t		fs_flags;
+	union {
+		struct {
+			int8_t	fs_fsmnt[512];
+			uint32_t	fs_cgrotor;
+			uint32_t	fs_csp[31];
+			uint32_t	fs_maxcluster;
+			uint32_t	fs_cpc;
+			uint16_t	fs_opostbl[16][8];
+		} PACKED fs_u1;
+		struct {
+			int8_t		fs_fsmnt[468];
+			uint8_t		fs_volname[32];
+			uint64_t	fs_swuid;
+			int32_t		fs_pad;
+			uint32_t	fs_cgrotor;
+			uint32_t	fs_ocsp[28];
+			uint32_t	fs_contigdirs;
+			uint32_t	fs_csp;	
+			uint32_t	fs_maxcluster;
+			uint32_t	fs_active;
+			int32_t		fs_old_cpc;
+			int32_t		fs_maxbsize;
+			int64_t		fs_sparecon64[17];
+			int64_t		fs_sblockloc;
+			struct ufs2_csum_total {
+				uint64_t	cs_ndir;
+				uint64_t	cs_nbfree;
+				uint64_t	cs_nifree;
+				uint64_t	cs_nffree;
+				uint64_t	cs_numclusters;
+				uint64_t	cs_spare[3];
+			} PACKED fs_cstotal;
+			struct ufs_timeval {
+				int32_t		tv_sec;
+				int32_t		tv_usec;
+			} PACKED fs_time;
+			int64_t		fs_size;
+			int64_t		fs_dsize;
+			uint64_t	fs_csaddr;
+			int64_t		fs_pendingblocks;
+			int32_t		fs_pendinginodes;
+		} PACKED fs_u2;
+	}  fs_u11;
+	union {
+		struct {
+			int32_t		fs_sparecon[53];
+			int32_t		fs_reclaim;
+			int32_t		fs_sparecon2[1];
+			int32_t		fs_state;
+			uint32_t	fs_qbmask[2];
+			uint32_t	fs_qfmask[2];
+		} PACKED fs_sun;
+		struct {
+			int32_t		fs_sparecon[53];
+			int32_t		fs_reclaim;
+			int32_t		fs_sparecon2[1];
+			uint32_t	fs_npsect;
+			uint32_t	fs_qbmask[2];
+			uint32_t	fs_qfmask[2];
+		} PACKED fs_sunx86;
+		struct {
+			int32_t		fs_sparecon[50];
+			int32_t		fs_contigsumsize;
+			int32_t		fs_maxsymlinklen;
+			int32_t		fs_inodefmt;
+			uint32_t	fs_maxfilesize[2];
+			uint32_t	fs_qbmask[2];
+			uint32_t	fs_qfmask[2];
+			int32_t		fs_state;
+		} PACKED fs_44;
+	} fs_u2;
+	int32_t		fs_postblformat;
+	int32_t		fs_nrpos;
+	int32_t		fs_postbloff;
+	int32_t		fs_rotbloff;
+	uint32_t	fs_magic;
+	uint8_t		fs_space[1];
+} PACKED;
+
+#define UFS_MAGIC			0x00011954
+#define UFS2_MAGIC			0x19540119
+#define UFS_MAGIC_FEA			0x00195612
+#define UFS_MAGIC_LFN			0x00095014
+
+int volume_id_probe_ufs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	uint32_t magic;
+	int i;
+	struct ufs_super_block *ufs;
+	int offsets[] = {0, 8, 64, 256, -1};
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	for (i = 0; offsets[i] >= 0; i++) {	
+		ufs = (struct ufs_super_block *) volume_id_get_buffer(id, off + (offsets[i] * 0x400), 0x800);
+		if (ufs == NULL)
+			return -1;
+
+		dbg("offset 0x%x", offsets[i] * 0x400);
+		magic = be32_to_cpu(ufs->fs_magic);
+		if ((magic == UFS_MAGIC) ||
+		    (magic == UFS2_MAGIC) ||
+		    (magic == UFS_MAGIC_FEA) ||
+		    (magic == UFS_MAGIC_LFN)) {
+			dbg("magic 0x%08x(be)", magic);
+			goto found;
+		}
+		magic = le32_to_cpu(ufs->fs_magic);
+		if ((magic == UFS_MAGIC) ||
+		    (magic == UFS2_MAGIC) ||
+		    (magic == UFS_MAGIC_FEA) ||
+		    (magic == UFS_MAGIC_LFN)) {
+			dbg("magic 0x%08x(le)", magic);
+			goto found;
+		}
+	}
+	return -1;
+
+found:
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "ufs";
+	switch (magic) {
+	case UFS_MAGIC:
+		strcpy(id->type_version, "1");
+		break;
+	case UFS2_MAGIC:
+		strcpy(id->type_version, "2");
+		volume_id_set_label_raw(id, ufs->fs_u11.fs_u2.fs_volname, 32);
+		volume_id_set_label_string(id, ufs->fs_u11.fs_u2.fs_volname, 32);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}

=== added file 'libvolume_id/util.c'
--- grub-0.97.orig/libvolume_id/util.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/util.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,472 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "strfuncs.h"
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+static char hex[] = "0123456789abcdef";
+
+#define hexhi(val)   hex[val >> 4]
+#define hexlo(val)   hex[val & 0xf]
+
+/* count of characters used to encode one unicode char */
+static int utf8_encoded_expected_len(const char *str)
+{
+	unsigned char c = (unsigned char)str[0];
+
+	if (c < 0x80)
+		return 1;
+	if ((c & 0xe0) == 0xc0)
+		return 2;
+	if ((c & 0xf0) == 0xe0)
+		return 3;
+	if ((c & 0xf8) == 0xf0)
+		return 4;
+	if ((c & 0xfc) == 0xf8)
+		return 5;
+	if ((c & 0xfe) == 0xfc)
+		return 6;
+	return 0;
+}
+
+/* decode one unicode char */
+static int utf8_encoded_to_unichar(const char *str)
+{
+	int unichar;
+	int len;
+	int i;
+
+	len = utf8_encoded_expected_len(str);
+	switch (len) {
+	case 1:
+		return (int)str[0];
+	case 2:
+		unichar = str[0] & 0x1f;
+		break;
+	case 3:
+		unichar = (int)str[0] & 0x0f;
+		break;
+	case 4:
+		unichar = (int)str[0] & 0x07;
+		break;
+	case 5:
+		unichar = (int)str[0] & 0x03;
+		break;
+	case 6:
+		unichar = (int)str[0] & 0x01;
+		break;
+	default:
+		return -1;
+	}
+
+	for (i = 1; i < len; i++) {
+		if (((int)str[i] & 0xc0) != 0x80)
+			return -1;
+		unichar <<= 6;
+		unichar |= (int)str[i] & 0x3f;
+	}
+
+	return unichar;
+}
+
+/* expected size used to encode one unicode char */
+static int utf8_unichar_to_encoded_len(int unichar)
+{
+	if (unichar < 0x80)
+		return 1;
+	if (unichar < 0x800)
+		return 2;
+	if (unichar < 0x10000)
+		return 3;
+	if (unichar < 0x200000)
+		return 4;
+	if (unichar < 0x4000000)
+		return 5;
+	return 6;
+}
+
+/* check if unicode char has a valid numeric range */
+static int utf8_unichar_valid_range(int unichar)
+{
+	if (unichar > 0x10ffff)
+		return 0;
+	if ((unichar & 0xfffff800) == 0xd800)
+		return 0;
+	if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
+		return 0;
+	if ((unichar & 0xffff) == 0xffff)
+		return 0;
+	return 1;
+}
+
+/* validate one encoded unicode char and return its length */
+int volume_id_utf8_encoded_valid_unichar(const char *str)
+{
+	int len;
+	int unichar;
+	int i;
+
+	len = utf8_encoded_expected_len(str);
+	if (len == 0)
+		return -1;
+
+	/* ascii is valid */
+	if (len == 1)
+		return 1;
+
+	/* check if expected encoded chars are available */
+	for (i = 0; i < len; i++)
+		if ((str[i] & 0x80) != 0x80)
+			return -1;
+
+	unichar = utf8_encoded_to_unichar(str);
+
+	/* check if encoded length matches encoded value */
+	if (utf8_unichar_to_encoded_len(unichar) != len)
+		return -1;
+
+	/* check if value has valid range */
+	if (!utf8_unichar_valid_range(unichar))
+		return -1;
+
+	return len;
+}
+
+size_t volume_id_set_unicode16(uint8_t *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count)
+{
+	size_t i, j;
+	uint16_t c;
+
+	j = 0;
+	for (i = 0; i + 2 <= count; i += 2) {
+		if (endianess == LE)
+			c = (buf[i+1] << 8) | buf[i];
+		else
+			c = (buf[i] << 8) | buf[i+1];
+		if (c == 0) {
+			str[j] = '\0';
+			break;
+		} else if (c < 0x80) {
+			if (j+1 >= len)
+				break;
+			str[j++] = (uint8_t) c;
+		} else if (c < 0x800) {
+			if (j+2 >= len)
+				break;
+			str[j++] = (uint8_t) (0xc0 | (c >> 6));
+			str[j++] = (uint8_t) (0x80 | (c & 0x3f));
+		} else {
+			if (j+3 >= len)
+				break;
+			str[j++] = (uint8_t) (0xe0 | (c >> 12));
+			str[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
+			str[j++] = (uint8_t) (0x80 | (c & 0x3f));
+		}
+	}
+	str[j] = '\0';
+	return j;
+}
+
+static char *usage_to_string(enum volume_id_usage usage_id)
+{
+	switch (usage_id) {
+	case VOLUME_ID_FILESYSTEM:
+		return "filesystem";
+	case VOLUME_ID_OTHER:
+		return "other";
+	case VOLUME_ID_RAID:
+		return "raid";
+	case VOLUME_ID_DISKLABEL:
+		return "disklabel";
+	case VOLUME_ID_CRYPTO:
+		return "crypto";
+	case VOLUME_ID_UNPROBED:
+		return "unprobed";
+	case VOLUME_ID_UNUSED:
+		return "unused";
+	}
+	return NULL;
+}
+
+void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id)
+{
+	id->usage_id = usage_id;
+	id->usage = usage_to_string(usage_id);
+}
+
+void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count)
+{
+	if (count > sizeof(id->label))
+		count = sizeof(id->label);
+
+	memcpy(id->label_raw, buf, count);
+	id->label_raw_len = count;
+}
+
+void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count)
+{
+	size_t i;
+
+	if (count >= sizeof(id->label))
+		count = sizeof(id->label)-1;
+
+	memcpy(id->label, buf, count);
+	id->label[count] = '\0';
+
+	/* remove trailing whitespace */
+	i = strnlen(id->label, count);
+	while (i--) {
+		if (!isspace(id->label[i]))
+			break;
+	}
+	id->label[i+1] = '\0';
+}
+
+void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count)
+{
+	if (count >= sizeof(id->label))
+		count = sizeof(id->label)-1;
+
+	 volume_id_set_unicode16((uint8_t *)id->label, sizeof(id->label), buf, endianess, count);
+}
+
+void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, size_t len, enum uuid_format format)
+{
+	unsigned int i;
+	unsigned int count = 0;
+	char *uuid;
+
+	if (len > sizeof(id->uuid_raw))
+		len = sizeof(id->uuid_raw);
+
+	switch(format) {
+	case UUID_STRING:
+		count = len;
+		break;
+	case UUID_HEX_STRING:
+		count = len;
+		break;
+	case UUID_DOS:
+		count = 4;
+		break;
+	case UUID_64BIT_LE:
+	case UUID_64BIT_BE:
+		count = 8;
+		break;
+	case UUID_DCE:
+		count = 16;
+		break;
+	case UUID_FOURINT:
+		count = 35;
+		break;
+	}
+	memcpy(id->uuid_raw, buf, count);
+	id->uuid_raw_len = count;
+
+	/* if set, create string in the same format, the native platform uses */
+	for (i = 0; i < count; i++)
+		if (buf[i] != 0)
+			goto set;
+	return;
+
+set:
+	uuid = id->uuid;
+	switch(format) {
+	case UUID_DOS:
+		*uuid++ = hexhi(buf[3]);
+		*uuid++ = hexlo(buf[3]);
+		*uuid++ = hexhi(buf[2]);
+		*uuid++ = hexlo(buf[2]);
+		*uuid++ = '-';
+		*uuid++ = hexhi(buf[1]);
+		*uuid++ = hexlo(buf[1]);
+		*uuid++ = hexhi(buf[0]);
+		*uuid++ = hexlo(buf[0]);
+		*uuid = '\0';
+		break;
+	case UUID_64BIT_LE:
+		*uuid++ = hexhi(buf[7]);
+		*uuid++ = hexlo(buf[7]);
+		*uuid++ = hexhi(buf[6]);
+		*uuid++ = hexlo(buf[6]);
+		*uuid++ = hexhi(buf[5]);
+		*uuid++ = hexlo(buf[5]);
+		*uuid++ = hexhi(buf[4]);
+		*uuid++ = hexlo(buf[4]);
+		*uuid++ = hexhi(buf[3]);
+		*uuid++ = hexlo(buf[3]);
+		*uuid++ = hexhi(buf[2]);
+		*uuid++ = hexlo(buf[2]);
+		*uuid++ = hexhi(buf[1]);
+		*uuid++ = hexlo(buf[1]);
+		*uuid++ = hexhi(buf[0]);
+		*uuid++ = hexlo(buf[0]);
+		*uuid = '\0';
+		break;
+	case UUID_64BIT_BE:
+		*uuid++ = hexhi(buf[0]);
+		*uuid++ = hexlo(buf[0]);
+		*uuid++ = hexhi(buf[1]);
+		*uuid++ = hexlo(buf[1]);
+		*uuid++ = hexhi(buf[2]);
+		*uuid++ = hexlo(buf[2]);
+		*uuid++ = hexhi(buf[3]);
+		*uuid++ = hexlo(buf[3]);
+		*uuid++ = hexhi(buf[4]);
+		*uuid++ = hexlo(buf[4]);
+		*uuid++ = hexhi(buf[5]);
+		*uuid++ = hexlo(buf[5]);
+		*uuid++ = hexhi(buf[6]);
+		*uuid++ = hexlo(buf[6]);
+		*uuid++ = hexhi(buf[7]);
+		*uuid++ = hexlo(buf[7]);
+		*uuid = '\0';
+		break;
+	case UUID_DCE:
+		*uuid++ = hexhi(buf[0]);
+		*uuid++ = hexlo(buf[0]);
+		*uuid++ = hexhi(buf[1]);
+		*uuid++ = hexlo(buf[1]);
+		*uuid++ = hexhi(buf[2]);
+		*uuid++ = hexlo(buf[2]);
+		*uuid++ = hexhi(buf[3]);
+		*uuid++ = hexlo(buf[3]);
+		*uuid++ = '-';
+		*uuid++ = hexhi(buf[4]);
+		*uuid++ = hexlo(buf[4]);
+		*uuid++ = hexhi(buf[5]);
+		*uuid++ = hexlo(buf[5]);
+		*uuid++ = '-';
+		*uuid++ = hexhi(buf[6]);
+		*uuid++ = hexlo(buf[6]);
+		*uuid++ = hexhi(buf[7]);
+		*uuid++ = hexlo(buf[7]);
+		*uuid++ = '-';
+		*uuid++ = hexhi(buf[8]);
+		*uuid++ = hexlo(buf[8]);
+		*uuid++ = hexhi(buf[9]);
+		*uuid++ = hexlo(buf[9]);
+		*uuid++ = '-';
+		*uuid++ = hexhi(buf[10]);
+		*uuid++ = hexlo(buf[10]);
+		*uuid++ = hexhi(buf[11]);
+		*uuid++ = hexlo(buf[11]);
+		*uuid++ = hexhi(buf[12]);
+		*uuid++ = hexlo(buf[12]);
+		*uuid++ = hexhi(buf[13]);
+		*uuid++ = hexlo(buf[13]);
+		*uuid++ = hexhi(buf[14]);
+		*uuid++ = hexlo(buf[14]);
+		*uuid++ = hexhi(buf[15]);
+		*uuid++ = hexlo(buf[15]);
+		*uuid = '\0';
+		break;
+	case UUID_HEX_STRING:
+		/* translate A..F to a..f */
+		memcpy(id->uuid, buf, count);
+		for (i = 0; i < count; i++)
+			if (id->uuid[i] >= 'A' && id->uuid[i] <= 'F')
+				id->uuid[i] = (id->uuid[i] - 'A') + 'a';
+		id->uuid[count] = '\0';
+		break;
+	case UUID_STRING:
+		memcpy(id->uuid, buf, count);
+		id->uuid[count] = '\0';
+		break;
+	case UUID_FOURINT:
+		*uuid++ = hexhi(buf[0]);
+		*uuid++ = hexlo(buf[0]);
+		*uuid++ = hexhi(buf[1]);
+		*uuid++ = hexlo(buf[1]);
+		*uuid++ = hexhi(buf[2]);
+		*uuid++ = hexlo(buf[2]);
+		*uuid++ = hexhi(buf[3]);
+		*uuid++ = hexlo(buf[3]);
+		*uuid++ = ':';
+		*uuid++ = hexhi(buf[4]);
+		*uuid++ = hexlo(buf[4]);
+		*uuid++ = hexhi(buf[5]);
+		*uuid++ = hexlo(buf[5]);
+		*uuid++ = hexhi(buf[6]);
+		*uuid++ = hexlo(buf[6]);
+		*uuid++ = hexhi(buf[7]);
+		*uuid++ = hexlo(buf[7]);
+		*uuid++ = ':';
+		*uuid++ = hexhi(buf[8]);
+		*uuid++ = hexlo(buf[8]);
+		*uuid++ = hexhi(buf[9]);
+		*uuid++ = hexlo(buf[9]);
+		*uuid++ = hexhi(buf[10]);
+		*uuid++ = hexlo(buf[10]);
+		*uuid++ = hexhi(buf[11]);
+		*uuid++ = hexlo(buf[11]);
+		*uuid++ = ':';
+		*uuid++ = hexhi(buf[12]);
+		*uuid++ = hexlo(buf[12]);
+		*uuid++ = hexhi(buf[13]);
+		*uuid++ = hexlo(buf[13]);
+		*uuid++ = hexhi(buf[14]);
+		*uuid++ = hexlo(buf[14]);
+		*uuid++ = hexhi(buf[15]);
+		*uuid++ = hexlo(buf[15]);
+		*uuid = '\0';
+		break;
+	default:
+		*uuid = '\0';
+		break;
+	}
+}
+
+uint8_t *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len)
+{
+	info("get buffer off 0x%llx(%llu), len 0x%zx", (unsigned long long) off, (unsigned long long) off, len);
+	/* check if requested area fits in superblock buffer */
+	if (off + len <= SB_BUFFER_SIZE) {
+		/* check if we need to read */
+		if ((off + len) > id->sbbuf_len) {
+			if (devread (0, 0, off + len, (char*)id->sbbuf) == 0)
+                        {
+				return NULL;
+                        }
+			id->sbbuf_len = off + len;
+		}
+		return &(id->sbbuf[off]);
+	} else {
+		if (len > SEEK_BUFFER_SIZE) {
+			dbg("seek buffer too small %d", SEEK_BUFFER_SIZE);
+			return NULL;
+		}
+
+		/* check if we need to read */
+		if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
+			info("read seekbuf off:0x%llx len:0x%zx", (unsigned long long) off, len);
+			if (devread(off >> 9, off & 0x1ff, len, (char*)id->seekbuf) == 0)
+			{
+				return NULL;
+			}
+			id->seekbuf_off = off;
+			id->seekbuf_len = len;
+		}
+		return &(id->seekbuf[off - id->seekbuf_off]);
+	}
+}

=== added file 'libvolume_id/util.h'
--- grub-0.97.orig/libvolume_id/util.h	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/util.h	2008-07-15 12:31:43 +0000
@@ -0,0 +1,98 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _VOLUME_ID_UTIL_
+#define _VOLUME_ID_UTIL_
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <endian.h>
+#include <byteswap.h>
+#include <syslog.h>
+
+#define ALLOWED_CHARS				"#+-.:=@_"
+
+#ifndef PACKED
+#define PACKED				__attribute__((packed))
+#endif
+
+#define err(format, arg...)	volume_id_log_fn(LOG_ERR, __FILE__, __LINE__, format, ##arg)
+#ifdef INFO
+#define info(format, arg...)	volume_id_log_fn(LOG_INFO, __FILE__, __LINE__, format, ##arg)
+#else
+#define info(format, arg...)    do { } while (0)
+#endif
+
+#ifdef DEBUG
+#define dbg(format, arg...)	volume_id_log_fn(LOG_DEBUG, __FILE__, __LINE__, format, ##arg)
+#else
+#define dbg(format, arg...)	do { } while (0)
+#endif
+
+/* size of superblock buffer, reiserfs block is at 64k */
+#define SB_BUFFER_SIZE				0x11000
+/* size of seek buffer, FAT cluster is 32k max */
+#define SEEK_BUFFER_SIZE			0x10000
+
+#ifdef __BYTE_ORDER
+#if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#define le16_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#define le64_to_cpu(x) (x)
+#define be16_to_cpu(x) bswap_16(x)
+#define be32_to_cpu(x) bswap_32(x)
+#define cpu_to_le16(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_be32(x) bswap_32(x)
+#elif (__BYTE_ORDER == __BIG_ENDIAN)
+#define le16_to_cpu(x) bswap_16(x)
+#define le32_to_cpu(x) bswap_32(x)
+#define le64_to_cpu(x) bswap_64(x)
+#define be16_to_cpu(x) (x)
+#define be32_to_cpu(x) (x)
+#define cpu_to_le16(x) bswap_16(x)
+#define cpu_to_le32(x) bswap_32(x)
+#define cpu_to_be32(x) (x)
+#endif
+#endif /* __BYTE_ORDER */
+
+enum uuid_format {
+	UUID_STRING,
+	UUID_HEX_STRING,
+	UUID_DCE,
+	UUID_DOS,
+	UUID_64BIT_LE,
+	UUID_64BIT_BE,
+	UUID_FOURINT,
+};
+
+enum endian {
+	LE = 0,
+	BE = 1
+};
+
+extern int volume_id_utf8_encoded_valid_unichar(const char *str);
+extern size_t volume_id_set_unicode16(uint8_t *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count);
+extern void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id);
+extern void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count);
+extern void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count);
+extern void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count);
+extern void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, size_t len, enum uuid_format format);
+extern uint8_t *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len);
+extern void volume_id_free_buffer(struct volume_id *id);
+
+#endif /* _VOLUME_ID_UTIL_ */
+

=== added file 'libvolume_id/via_raid.c'
--- grub-0.97.orig/libvolume_id/via_raid.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/via_raid.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,88 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ * Based on information taken from dmraid:
+ * Copyright (C) 2004-2006 Heinz Mauelshagen, Red Hat GmbH
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct via_meta {
+	uint16_t	signature;
+	uint8_t		version_number;
+	struct via_array {
+		uint16_t	disk_bit_mask;
+		uint8_t		disk_array_ex;
+		uint32_t	capacity_low;
+		uint32_t	capacity_high;
+		uint32_t	serial_checksum;
+	} PACKED array;
+	uint32_t	serial_checksum[8];
+	uint8_t		checksum;
+} PACKED;
+
+#define VIA_SIGNATURE		0xAA55
+
+/* 8 bit checksum on first 50 bytes of metadata. */
+static uint8_t meta_checksum(struct via_meta *via)
+{
+	uint8_t i = 50, sum = 0;
+
+	while (i--)
+		sum += ((uint8_t*) via)[i];
+
+	return sum == via->checksum;
+}
+
+
+int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	const uint8_t *buf;
+	uint64_t meta_off;
+	struct via_meta *via;
+
+	dbg("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	if (size < 0x10000)
+		return -1;
+
+	meta_off = ((size / 0x200)-1) * 0x200;
+
+	buf = volume_id_get_buffer(id, off + meta_off, 0x200);
+	if (buf == NULL)
+		return -1;
+
+	via = (struct via_meta *) buf;
+	if (le16_to_cpu(via->signature) !=  VIA_SIGNATURE)
+		return -1;
+
+	if (via->version_number > 1)
+		return -1;
+
+	if (!meta_checksum(via))
+		return -1;
+
+	volume_id_set_usage(id, VOLUME_ID_RAID);
+	sprintf(id->type_version, "%u", via->version_number);
+	id->type = "via_raid_member";
+
+	return 0;
+}

=== added file 'libvolume_id/volume_id.c'
--- grub-0.97.orig/libvolume_id/volume_id.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/volume_id.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,222 @@
+/*
+ * volume_id - reads volume label and uuid
+ *
+ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
+ * Grub Port, Copyright (C) 2008 Canonical Ltd.
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include "volume_id.h"
+#include "util.h"
+#include "strfuncs.h"
+#include "shared.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+struct prober {
+	volume_id_probe_fn_t prober;
+	const char *name[4];
+};
+
+#define NOT_SUPPORTED(x)	
+#define SUPPORTED(x)	x
+
+static const struct prober prober_raid[] = {
+	{ volume_id_probe_ddf_raid, { "ddf_raid", } },
+
+	/* { volume_id_probe_linux_raid, { "linux_raid", } },  */
+	/* { volume_id_probe_intel_software_raid, { "isw_raid", } }, */
+	/* { volume_id_probe_lsi_mega_raid, { "lsi_mega_raid", } }, */
+	/* { volume_id_probe_via_raid, { "via_raid", } }, */
+	/* { volume_id_probe_silicon_medley_raid, { "silicon_medley_raid", } }, */
+	/* { volume_id_probe_nvidia_raid, { "nvidia_raid", } }, */
+	/* { volume_id_probe_promise_fasttrack_raid, { "promise_fasttrack_raid", } }, */
+	/* { volume_id_probe_highpoint_45x_raid, { "highpoint_raid", } }, */
+	/* { volume_id_probe_adaptec_raid, { "adaptec_raid", } }, */
+	/* { volume_id_probe_jmicron_raid, { "jmicron_raid", } }, */
+	/* { volume_id_probe_lvm1, { "lvm1", } }, */
+	/* { volume_id_probe_lvm2, { "lvm2", } }, */
+	/* { volume_id_probe_highpoint_37x_raid, { "highpoint_raid", } }, */
+};
+
+static const struct prober prober_filesystem[] = {
+	{ volume_id_probe_vfat, { "vfat", } }, 
+	{ volume_id_probe_luks, { "luks", } }, 
+	{ volume_id_probe_xfs, { "xfs", } }, 
+	{ volume_id_probe_ext, { "ext2", "ext3", "jbd", } }, 
+	{ volume_id_probe_reiserfs, { "reiserfs", "reiser4", } }, 
+	{ volume_id_probe_jfs, { "jfs", } }, 
+	{ volume_id_probe_hfs_hfsplus, { "hfs", "hfsplus", } }, 
+	{ volume_id_probe_ntfs, { "ntfs", } },
+ 	{ volume_id_probe_ocfs1, { "ocfs1", } },
+	{ volume_id_probe_ocfs2, { "ocfs2", } }, 
+
+	/* { volume_id_probe_linux_swap, { "swap", } }, */
+	/* { volume_id_probe_udf, { "udf", } }, */
+	/* { volume_id_probe_iso9660, { "iso9660", } }, */
+	/* { volume_id_probe_ufs, { "ufs", } },  */
+	/* { volume_id_probe_cramfs, { "cramfs", } }, */
+	/* { volume_id_probe_romfs, { "romfs", } }, */
+	/* { volume_id_probe_hpfs, { "hpfs", } }, */
+	/* { volume_id_probe_sysv, { "sysv", "xenix", } }, */
+	/* { volume_id_probe_minix, { "minix",  } }, */
+	/* { volume_id_probe_vxfs, { "vxfs", } }, */
+	/* { volume_id_probe_squashfs, { "squashfs", } }, */
+	/* { volume_id_probe_netware, { "netware", } }, */
+};
+
+/* the user can overwrite this log function */
+static void default_log(int priority, const char *file, int line, const char *format, ...)
+{
+	return;
+}
+
+volume_id_log_fn_t volume_id_log_fn = default_log;
+
+/**
+ * volume_id_get_type:
+ * @id: Probing context
+ * @type: Type string. Must not be freed by the caller.
+ *
+ * Get the type string after a successful probe.
+ *
+ * Returns: 1 if the value was set, 0 otherwise.
+ **/
+int volume_id_get_type(struct volume_id *id, const char **type)
+{
+	if (id == NULL)
+		return 0;
+	if (type == NULL)
+		return 0;
+	if (id->usage_id == VOLUME_ID_UNUSED)
+		return 0;
+
+	*type = id->type;
+	return 1;
+}
+
+
+/**
+ * volume_id_get_uuid:
+ * @id: Probing context.
+ * @uuid: UUID string. Must not be freed by the caller.
+ *
+ * Get the raw UUID string after a successful probe.
+ *
+ * Returns: 1 if the value was set, 0 otherwise.
+ **/
+int volume_id_get_uuid(struct volume_id *id, const char **uuid)
+{
+	if (id == NULL)
+		return 0;
+	if (uuid == NULL)
+		return 0;
+	if (id->usage_id == VOLUME_ID_UNUSED)
+		return 0;
+
+	*uuid = id->uuid;
+	return 1;
+}
+
+/**
+ * volume_id_probe_raid:
+ * @id: Probing context.
+ * @off: Probing offset relative to the start of the device.
+ * @size: Total size of the device.
+ *
+ * Probe device for all known raid signatures.
+ *
+ * Returns: 0 on successful probe, otherwise negative value.
+ **/
+int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	unsigned int i;
+
+	if (id == NULL)
+		return -1;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	for (i = 0; i < ARRAY_SIZE(prober_raid); i++)
+		if (prober_raid[i].prober(id, off, size) == 0)
+			goto found;
+	return -1;
+
+found:
+	return 0;
+}
+
+/**
+ * volume_id_probe_filesystem:
+ * @id: Probing context.
+ * @off: Probing offset relative to the start of the device.
+ * @size: Total size of the device.
+ *
+ * Probe device for all known filesystem signatures.
+ *
+ * Returns: 0 on successful probe, otherwise negative value.
+ **/
+int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	unsigned int i;
+
+	if (id == NULL)
+		return -1;
+
+	info("probing at offset 0x%llx, size 0x%llx",
+	    (unsigned long long) off, (unsigned long long) size);
+
+	for (i = 0; i < ARRAY_SIZE(prober_filesystem); i++)
+		if (prober_filesystem[i].prober(id, off, size) == 0)
+			goto found;
+	return -1;
+
+found:
+	return 0;
+}
+
+/**
+ * volume_id_probe_raid:
+ * @all_probers_fn: prober function to called for all known probing routines.
+ * @id: Context passed to prober function.
+ * @off: Offset value passed to prober function.
+ * @size: Size value passed to prober function.
+ * @data: Arbitrary data passed to the prober function.
+ *
+ * Run a custom function for all known probing routines.
+ **/
+void volume_id_all_probers(all_probers_fn_t all_probers_fn,
+			   struct volume_id *id, uint64_t off, uint64_t size,
+			   void *data)
+{
+	unsigned int i;
+
+	if (all_probers_fn == NULL)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(prober_raid); i++) {	
+		if (all_probers_fn(prober_raid[i].prober, id, off, size, data) != 0)
+			goto out;
+	}
+	for (i = 0; i < ARRAY_SIZE(prober_filesystem); i++) {
+		if (all_probers_fn(prober_filesystem[i].prober, id, off, size, data) != 0)
+			goto out;
+	}
+out:
+	return;
+}

=== added file 'libvolume_id/volume_id.h'
--- grub-0.97.orig/libvolume_id/volume_id.h	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/volume_id.h	2008-07-15 12:31:43 +0000
@@ -0,0 +1,137 @@
+/*
+ * volume_id - reads volume label and uuid
+ *
+ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _LIBVOLUME_ID_H_
+#define _LIBVOLUME_ID_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef void (*volume_id_log_fn_t)(int priority, const char *file, int line, const char *format, ...) ;
+
+extern volume_id_log_fn_t volume_id_log_fn;
+
+struct volume_id;
+typedef int (*volume_id_probe_fn_t)(struct volume_id *id, uint64_t off, uint64_t size);
+typedef int (*all_probers_fn_t)(volume_id_probe_fn_t probe_fn,
+				struct volume_id *id, uint64_t off, uint64_t size,
+				void *data);
+
+extern struct volume_id *volume_id_open_fd(int fd);
+extern void volume_id_close(struct volume_id *id);
+extern int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size);
+extern const volume_id_probe_fn_t *volume_id_get_prober_by_type(const char *type);
+extern void volume_id_all_probers(all_probers_fn_t all_probers_fn,
+				  struct volume_id *id, uint64_t off, uint64_t size,
+				  void *data);
+extern int volume_id_get_label(struct volume_id *id, const char **label);
+extern int volume_id_get_label_raw(struct volume_id *id, const uint8_t **label, size_t *len);
+extern int volume_id_get_uuid(struct volume_id *id, const char **uuid);
+extern int volume_id_get_uuid_raw(struct volume_id *id, const uint8_t **uuid, size_t *len);
+extern int volume_id_get_usage(struct volume_id *id, const char **usage);
+extern int volume_id_get_type(struct volume_id *id, const char **type);
+extern int volume_id_get_type_version(struct volume_id *id, const char **type_version);
+extern int volume_id_encode_string(const char *str, char *str_enc, size_t len);
+
+/*
+ * Note: everything below will be made private or removed from
+ * a future version, and a new major release of libvolume_id
+ */
+
+extern struct volume_id *volume_id_open_node(const char *path);
+
+#define VOLUME_ID_LABEL_SIZE		64
+#define VOLUME_ID_UUID_SIZE		36
+#define VOLUME_ID_FORMAT_SIZE		32
+#define VOLUME_ID_PATH_MAX		256
+#define VOLUME_ID_PARTITIONS_MAX	256
+
+enum volume_id_usage {
+	VOLUME_ID_UNUSED,
+	VOLUME_ID_UNPROBED,
+	VOLUME_ID_OTHER,
+	VOLUME_ID_FILESYSTEM,
+	VOLUME_ID_RAID,
+	VOLUME_ID_DISKLABEL,
+	VOLUME_ID_CRYPTO,
+};
+
+#include <util.h>
+
+struct volume_id {
+	uint8_t		label_raw[VOLUME_ID_LABEL_SIZE];
+	size_t		label_raw_len;
+	char		label[VOLUME_ID_LABEL_SIZE+1];
+	uint8_t		uuid_raw[VOLUME_ID_UUID_SIZE];
+	size_t		uuid_raw_len;
+	char		uuid[VOLUME_ID_UUID_SIZE+1];
+	enum		volume_id_usage usage_id;
+	char		*usage;
+	char		*type;
+	char		type_version[VOLUME_ID_FORMAT_SIZE];
+
+	int		fd;
+	uint8_t		sbbuf[SB_BUFFER_SIZE];
+	size_t		sbbuf_len;
+	uint8_t		seekbuf[SEEK_BUFFER_SIZE];
+	uint64_t	seekbuf_off;
+	size_t		seekbuf_len;
+	int		fd_close:1;
+};
+
+/* filesystems */
+extern int volume_id_probe_cramfs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_ext(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_vfat(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_hpfs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_iso9660(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_jfs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_minix(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_ntfs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_ocfs1(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_romfs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_sysv(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_udf(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_ufs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_vxfs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_xfs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_squashfs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_netware(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_gfs(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_gfs2(struct volume_id *id, uint64_t off, uint64_t size);
+
+/* special formats */
+extern int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_luks(struct volume_id *id, uint64_t off, uint64_t size);
+
+/* raid */
+extern int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_lvm1(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_lvm2(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_ddf_raid(struct volume_id *id, uint64_t off, uint64_t size);
+
+/* bios raid */
+extern int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_adaptec_raid(struct volume_id *id, uint64_t off, uint64_t size);
+extern int volume_id_probe_jmicron_raid(struct volume_id *id, uint64_t off, uint64_t size);
+
+#endif

=== added file 'libvolume_id/vxfs.c'
--- grub-0.97.orig/libvolume_id/vxfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/vxfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,49 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+#define VXFS_SUPER_MAGIC	0xa501FCF5
+
+struct vxfs_super {
+	uint32_t		vs_magic;
+	int32_t			vs_version;
+} PACKED;
+
+int volume_id_probe_vxfs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct vxfs_super *vxs;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	vxs = (struct vxfs_super *) volume_id_get_buffer(id, off + 0x200, 0x200);
+	if (vxs == NULL)
+		return -1;
+
+	if (vxs->vs_magic == cpu_to_le32(VXFS_SUPER_MAGIC)) {
+		sprintf(id->type_version, "%u", (unsigned int) vxs->vs_version);
+		volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+		id->type = "vxfs";
+		return 0;
+	}
+
+	return -1;
+}

=== added file 'libvolume_id/xfs.c'
--- grub-0.97.orig/libvolume_id/xfs.c	1970-01-01 00:00:00 +0000
+++ grub-0.97/libvolume_id/xfs.c	2008-07-15 12:31:43 +0000
@@ -0,0 +1,59 @@
+/*
+ * volume_id - reads filesystem label and uuid
+ *
+ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ *	This program is free software; you can redistribute it and/or modify it
+ *	under the terms of the GNU General Public License as published by the
+ *	Free Software Foundation version 2 of the License.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "volume_id.h"
+#include "util.h"
+#include "shared.h"
+
+struct xfs_super_block {
+	uint8_t	magic[4];
+	uint32_t	blocksize;
+	uint64_t	dblocks;
+	uint64_t	rblocks;
+	uint32_t	dummy1[2];
+	uint8_t	uuid[16];
+	uint32_t	dummy2[15];
+	uint8_t	fname[12];
+	uint32_t	dummy3[2];
+	uint64_t	icount;
+	uint64_t	ifree;
+	uint64_t	fdblocks;
+} PACKED;
+
+int volume_id_probe_xfs(struct volume_id *id, uint64_t off, uint64_t size)
+{
+	struct xfs_super_block *xs;
+
+	info("probing at offset 0x%llx", (unsigned long long) off);
+
+	xs = (struct xfs_super_block *) volume_id_get_buffer(id, off, 0x200);
+	if (xs == NULL)
+		return -1;
+
+	if (memcmp((char *)xs->magic, "XFSB", 4) != 0)
+		return -1;
+
+	volume_id_set_label_raw(id, xs->fname, 12);
+	volume_id_set_label_string(id, xs->fname, 12);
+	volume_id_set_uuid(id, xs->uuid, 0, UUID_DCE);
+
+	volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
+	id->type = "xfs";
+
+	return 0;
+}

=== modified file 'stage2/Makefile.am'
--- grub-0.97.orig/stage2/Makefile.am	2005-02-02 20:40:05 +0000
+++ grub-0.97/stage2/Makefile.am	2008-07-09 17:23:44 +0000
@@ -13,6 +13,10 @@
 # For <stage1.h>.
 INCLUDES = -I$(top_srcdir)/stage1
 
+if UUID_SUPPORT
+INCLUDES += -I$(top_srcdir)/libvolume_id
+endif
+
 # The library for /sbin/grub.
 noinst_LIBRARIES = libgrub.a
 libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
@@ -61,6 +65,12 @@
 PXELOADER_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
 START_ELTORITO_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
 
+if UUID_SUPPORT
+UUID_FLAGS = -DSUPPORT_UUID=1
+else
+UUID_FLAGS =
+endif
+
 if NETBOOT_SUPPORT
 NETBOOT_FLAGS = -I$(top_srcdir)/netboot -DSUPPORT_NETBOOT=1
 else
@@ -82,6 +92,8 @@
 STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
 	$(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS)
 
+STAGE2_COMPILE += $(UUID_FLAGS)
+
 STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000
 STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1
 
@@ -97,7 +109,12 @@
 
 if NETBOOT_SUPPORT
 pre_stage2_exec_LDADD = ../netboot/libdrivers.a
-endif
+else
+if UUID_SUPPORT
+pre_stage2_exec_LDADD = ../libvolume_id/libvolume_id.a
+endif
+endif
+
 
 if DISKLESS_SUPPORT
 BUILT_SOURCES = stage2_size.h diskless_size.h

=== modified file 'stage2/builtins.c'
--- grub-0.97.orig/stage2/builtins.c	2008-01-28 18:15:31 +0000
+++ grub-0.97/stage2/builtins.c	2008-07-09 17:23:44 +0000
@@ -49,6 +49,10 @@
 # include <md5.h>
 #endif
 
+#ifdef SUPPORT_UUID
+#include <volume_id.h>
+#endif
+
 /* The type of kernel loaded.  */
 kernel_t kernel_type;
 /* The boot device.  */
@@ -4790,6 +4794,168 @@
   "Probe VBE information. If the mode number MODE is specified, show only"
   " the information about only the mode."
 };
+
+
+
+#ifdef SUPPORT_UUID
+
+struct uuid_callback_data
+{
+   int  found;	/* 1 if uuid matches */
+   char *uuid;  /* uuid to look for */
+};
+
+static void uuid_info_print(struct volume_id *id, const char *uuid)
+{
+  const char *type;
+  int i;
+
+  volume_id_get_type(id, &type);
+  grub_printf("(hd%d", current_drive - 0x80);
+  if ((current_partition & 0xFF0000) != 0xFF0000)
+    {
+      grub_printf (",%d", (current_partition >> 16) & 0xFF);
+    }
+  if ((current_partition & 0x00FF00) != 0x00FF00)
+    {
+      grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF));
+    }
+  grub_printf(") %s",type);
+  for (i=0;i<6-strlen(type);i++)
+    {
+      grub_putchar(' ');
+    }
+  grub_printf(" %s\n",uuid);
+}
+
+static int uuid_all_probers(volume_id_probe_fn_t probe_fn,
+                            struct volume_id *id, 
+			    uint64_t off, 
+			    uint64_t size, 
+			    void *data)
+{
+  struct uuid_callback_data *uc_data = (struct uuid_callback_data*)data;
+
+  if (probe_fn(id, off, size) == 0)
+    {
+      const char *volume_uuid;
+      if (volume_id_get_uuid(id, &volume_uuid)) 
+        {
+          if (!*(uc_data->uuid))
+            { 
+              uuid_info_print(id, volume_uuid);
+            }
+          else
+           {
+              if (strcmp(volume_uuid, uc_data->uuid) == 0) 
+                {
+                  grub_printf("Boot from ");
+                  uuid_info_print(id, volume_uuid);
+                  uc_data->found = 1;
+                  return 1;
+                }
+            }
+        }
+    }
+  return 0;
+}
+
+/* uuid find */
+/* Search for the uuid arg in all of partitions.  */
+static int
+uuid_func(char *arg, int flag)
+{
+  unsigned long drive;
+  unsigned long tmp_drive = saved_drive;
+  unsigned long tmp_partition = saved_partition;
+  struct uuid_callback_data uc_data;
+
+  uc_data.uuid = arg;
+  uc_data.found = 0;
+
+  /* Just hard disks and USB drives supported by BIOS  */
+  for (drive = 0x80; drive < 0x88; drive++)
+    {
+      unsigned long part = 0xFFFFFF;
+      unsigned long start, len, offset, ext_offset, gpt_offset;
+      int type, entry, gpt_count, gpt_size;
+      char *buf = (char *) RAW_ADDR(0x100000);
+      struct volume_id *vol_id = (struct volume_id *) RAW_ADDR (0x100000 + SECTOR_SIZE);
+
+      current_drive = drive;
+      while (next_partition (drive, 0xFFFFFF, &part, &type,
+			     &start, &len, &offset, &entry,
+			     &ext_offset, &gpt_offset,
+			     &gpt_count, &gpt_size, buf))
+	{
+	  if (type != PC_SLICE_TYPE_NONE
+	      && ! IS_PC_SLICE_TYPE_BSD (type)
+	      && ! IS_PC_SLICE_TYPE_EXTENDED (type))
+	    {
+	      current_partition = part;
+              errnum = ERR_NONE;
+              /* Attempt to open device, conventional way */
+              if (! open_device ())
+                {
+                  errnum = ERR_NONE;
+                  /* Failed, like NTFS or FAT filesystems, so try the rootnoverify way */
+                  if (open_partition ())
+                    {
+                      set_bootdev (0);
+                      if (errnum)
+                        {
+                          /* Give up */
+                          errnum = ERR_NONE;
+                          continue;
+                        }
+                    }
+                }
+
+              /* And probe for uuid across all fs types */
+              saved_drive = current_drive;
+              saved_partition = current_partition;
+		
+              grub_memset(vol_id, 0, sizeof(struct volume_id) );
+              volume_id_all_probers(uuid_all_probers, vol_id, 0, len, (void*)&uc_data);
+              if (uc_data.found)
+                {
+                  /* Success! */
+                  errnum = ERR_NONE;
+                  return 0;
+                }
+	    }
+	  /* We want to ignore any error here.  */
+	  errnum = ERR_NONE;
+	}
+
+      /* next_partition always sets ERRNUM in the last call, so clear it.  */
+      errnum = ERR_NONE;
+    }
+
+  saved_drive = tmp_drive;
+  saved_partition = tmp_partition;
+  current_drive = GRUB_INVALID_DRIVE;
+  current_partition = 0xFFFFFF;
+  errnum = ERR_FILE_NOT_FOUND;
+
+  if (!*arg) 
+    {
+      errnum = ERR_NONE;
+      return 0;
+    }
+  return 1;
+}
+
+static struct builtin builtin_uuid =
+{
+  "uuid",
+  uuid_func,
+  BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+  "uuid UUID",
+  "Set the current \"root device\" to the device with the uuid UUID,"
+  " then attempt to mount it"
+};
+#endif
   
 
 /* The table of builtin commands. Sorted in dictionary order.  */
@@ -4879,6 +5045,9 @@
   &builtin_title,
   &builtin_unhide,
   &builtin_uppermem,
+#ifdef SUPPORT_UUID
+  &builtin_uuid,
+#endif
   &builtin_vbeprobe,
   0
 };